Does Go Have Classes?
Go does not have a class keyword or traditional class-based inheritance. Instead, Go programs model data and behavior by combining struct types, methods, interfaces, and composition.
A struct stores related fields, while methods define behavior for that struct type. This combination can serve many of the same purposes as a class in languages such as Java, C++, or C#.
How Go Represents Class-Like Data and Behavior
- Struct: groups related data fields.
- Methods: attach behavior to a named type.
- Constructor function: creates and initializes a value by convention.
- Interfaces: describe behavior without requiring an explicit declaration that a type implements them.
- Embedding: supports composition and method promotion instead of class inheritance.
Go Struct with a Method: Class-Like Example
In the following example, we define a class-like type using Go structs. The Student struct stores data, and the PrintDetails method defines behavior associated with that type.
example.go
package main
import "fmt"
// struct definition
type Student struct {
name string
rollNumber int
}
// associate method to Strudent struct type
func (s Student) PrintDetails() {
fmt.Println("Student Details\n---------------")
fmt.Println("Name :", s.name)
fmt.Println("Roll Number :", s.rollNumber)
}
func main() {
var stud1 = Student{name:"Anu", rollNumber:14}
stud1.PrintDetails()
}
Output
Student Details
---------------
Name : Anu
Roll Number : 14
Here, Student is a named struct type. The method receiver (s Student) associates PrintDetails with that type. The expression stud1.PrintDetails() calls the method on a Student value.
Struct and Method Compared with a Traditional Class
The Student struct is analogous to a class below provided in pseudo code.
Pseudo Code
class Student{
name
rollnumber
function PrintDetails(){
// print details using this.name, this.rollnumber
}
}
The comparison is conceptual rather than exact. Go does not provide constructors, access modifiers, inheritance hierarchies, or method overloading in the same form as traditional object-oriented languages.
Constructor Functions for Go Struct Types
Go does not have a constructor keyword. A common convention is to create a function named NewTypeName that initializes and returns a value or pointer.
package main
import "fmt"
type Student struct {
Name string
RollNumber int
}
func NewStudent(name string, rollNumber int) *Student {
return &Student{
Name: name,
RollNumber: rollNumber,
}
}
func (s Student) PrintDetails() {
fmt.Println("Name:", s.Name)
fmt.Println("Roll Number:", s.RollNumber)
}
func main() {
student := NewStudent("Anu", 14)
student.PrintDetails()
}
The NewStudent function is an ordinary Go function. Its name signals that it creates a properly initialized Student. Returning a pointer is useful when methods need to modify the same value or when copying the struct would be inefficient.
Value Receivers and Pointer Receivers in Go Methods
A method can use either a value receiver or a pointer receiver.
- A value receiver, such as
func (s Student), receives a copy of the value. - A pointer receiver, such as
func (s *Student), can modify the original value.
package main
import "fmt"
type Student struct {
Name string
}
func (s *Student) Rename(newName string) {
s.Name = newName
}
func main() {
student := Student{Name: "Anu"}
student.Rename("Asha")
fmt.Println(student.Name)
}
Output
Asha
The Rename method uses *Student, so changing s.Name updates the original student variable.
Encapsulation with Exported and Unexported Go Fields
Go controls visibility through identifier capitalization rather than keywords such as public and private.
- An identifier beginning with an uppercase letter, such as
Name, is exported from its package. - An identifier beginning with a lowercase letter, such as
name, is accessible only within the same package.
This package-level visibility provides encapsulation without class-specific access modifiers.
Go Interfaces as Behavior Contracts
An interface specifies one or more method signatures. A type satisfies an interface automatically when it implements the required methods. There is no separate implements declaration.
package main
import "fmt"
type Printer interface {
PrintDetails()
}
type Student struct {
Name string
}
func (s Student) PrintDetails() {
fmt.Println("Student:", s.Name)
}
func PrintRecord(p Printer) {
p.PrintDetails()
}
func main() {
student := Student{Name: "Anu"}
PrintRecord(student)
}
Because Student has a PrintDetails() method, it satisfies the Printer interface. This allows functions to depend on required behavior instead of a particular concrete type.
Composition and Struct Embedding Instead of Inheritance
Go does not support class inheritance. It favors composition, where one struct contains or embeds another type.
package main
import "fmt"
type Person struct {
Name string
}
func (p Person) Greet() {
fmt.Println("Hello,", p.Name)
}
type Student struct {
Person
RollNumber int
}
func main() {
student := Student{
Person: Person{Name: "Anu"},
RollNumber: 14,
}
student.Greet()
fmt.Println("Roll Number:", student.RollNumber)
}
The embedded Person field promotes its Greet method, allowing it to be called as student.Greet(). This is composition and method promotion, not an inheritance relationship.
Key Differences Between Go Structs and Classes
| Class-based concept | Go approach |
|---|---|
| Class declaration | Named struct type |
| Instance methods | Methods with value or pointer receivers |
| Constructor | Ordinary factory function, commonly named NewType |
| Public and private members | Exported and unexported identifiers based on capitalization |
| Inheritance | Composition and struct embedding |
| Interface implementation declaration | Implicit interface satisfaction |
| Method overloading | Not supported; methods must have distinct names |
Common Mistakes When Modeling Classes in Go
- Trying to reproduce inheritance hierarchies: prefer small interfaces and composition.
- Using a value receiver for a modifying method: use a pointer receiver when the method must change the original value.
- Exporting every field: keep implementation details unexported unless other packages need direct access.
- Creating interfaces too early: define interfaces around behavior that callers actually require.
- Assuming embedding means inheritance: embedded fields do not create an is-a relationship or support method overriding in the traditional class sense.
Frequently Asked Questions About Classes in Go
Is there a class keyword in Go?
No. Go has no class keyword. Class-like designs are usually created with structs, methods, interfaces, and composition.
How do you create an object in Go?
You create a value of a struct type using a struct literal, the new built-in function, or a constructor-style function such as NewStudent. Go normally refers to these as values rather than objects.
Can a Go struct have methods?
Yes. Methods can be declared on any defined non-interface type whose definition is in the same package. Struct types are the most common receivers.
Does Go support inheritance?
No. Go does not support class inheritance. It uses composition, embedding, and interfaces to reuse behavior and build abstractions.
When should a Go method use a pointer receiver?
Use a pointer receiver when the method must modify the receiver, when copying the value would be costly, or when receiver consistency requires the type’s methods to use pointers.
Go Class-Like Design Summary
Go does not implement classes directly. A named struct defines data, methods define behavior, constructor-style functions initialize values, interfaces provide behavioral abstraction, and embedding supports composition. Together, these features cover many common class use cases while keeping type relationships explicit and relatively simple.
In this Go Tutorial, we learned how to work with the class concept in Go using structs, methods, constructor functions, interfaces, pointer receivers, and composition.
Editorial QA Checklist for This Go Class Tutorial
- Confirm that the tutorial clearly states that Go has no
classkeyword and no class inheritance. - Verify that every Go example compiles and that shown output matches the program.
- Check that value receivers and pointer receivers are described accurately.
- Ensure that exported and unexported identifiers are explained as package-level visibility rules.
- Confirm that struct embedding is described as composition and method promotion, not traditional inheritance.
TutorialKart.com