What a "class" means in Go
Go has no class keyword. The job a class does in other languages, bundling data and behaviour under one name so you can model a Dog, a BankAccount or a Game, is done by a struct type. You declare the data as fields of the struct, and you attach behaviour with methods, which later lessons add one piece at a time.
This lesson covers the first piece: declaring a new type. The lesson's examples call fmt.Println, so they assume import "fmt" at the top of the file.
The syntax
type Dog struct {
}
Reading it from left to right:
typetells Go you are declaring a new type.Dogis the name you chose. Go programmers write type names in PascalCase:Dog,BankAccount,HighScore. A capital first letter also has a meaning, covered in the access modifiers lesson.structsays the type is a record made of fields.- The braces hold the fields. Here they are empty, which is a valid type. A struct with no fields is a normal type, and it is common for types that only carry methods.
Go needs no semicolon after the closing brace. A one-line form is equally valid:
type Dog struct{}
Creating a value of the type
Once Dog exists, Dog{} creates a value of it. This is a composite literal: the type name followed by braces. With no fields to fill in, the braces stay empty.
dog := Dog{}
fmt.Println(dog)
This prints {}, the default formatting of a struct with no fields. The next lessons cover creating values in more detail and giving the struct fields.
Types with behaviour: receivers
You give a type behaviour by declaring a function with a receiver, the parameter in parentheses between func and the method name:
type Dog struct {
}
func (d Dog) bark() {
fmt.Println("Woof!")
}
Now any Dog value can call bark with dot syntax, for example dog.bark(). The method lives outside the braces of the struct. In Go, the type declaration holds only the data, and methods are declared separately, anywhere in the same package. The lessons in this chapter use the receiver name this, borrowed from other languages. Most Go code uses a short name based on the type, such as d for Dog, and both compile.
The lesson's exercise
The task is to declare an empty struct type called Dog. The code already in mainFunction creates a Dog and prints a confirmation, so the only missing piece is the type.
- Write the declaration at the top of the file, outside any function, because type declarations and function declarations both live at the package level.
- Use the exact name
Dog. Go is case-sensitive, sodogwould be a different identifier from theDogthatmainFunctionuses.
type Dog struct {}
func mainFunction() {
dog := Dog{}
_ = dog
fmt.Println("Defined the Dog class!")
}
The program prints:
Defined the Dog class!
The line _ = dog is there because Go refuses to compile a function that declares a local variable and never uses it. Assigning the value to the blank identifier _ counts as a use that discards it.
Common mistakes
- Looking for the
classkeyword. There is none. Writingclass Dog {}is a syntax error. - Putting the declaration inside a function by accident. That is legal, but then the type exists only inside that function, so
mainFunctionwould not see it. - Using the type without the braces.
dog := Dogdoes not compile, becauseDogis a type and not a value. WriteDog{}. - Declaring a variable and not using it. An unused local variable is a compile error in Go, not a warning.
- Adding a semicolon after the braces out of habit from C++. It is not needed.
Key takeaways
- A struct type is Go's replacement for a class:
type Name struct { ... }. - The body may be empty, and the type is still real.
- Create a value with a composite literal such as
Dog{}. - Behaviour comes from methods with a receiver, declared outside the struct.
- Type names use PascalCase by convention.