Structs
If you have a background in Object Oriented Program, you are likely familiar with the concept of classes. Go does not provide classes, but instead defines typed collections of fields as structs. A struct can have both field and methods. Structs can also embed other structs.
Let's look at an example of a struct with fields:
package main
import "fmt"
// A Person has qualities of a human
type Person struct {
first string
last string
}
func main() {
p := &Person{ // you can create new struct instances with :=
first: "Ada",
last: "Lovelace",
}
fmt.Println(p.first) // we can access "first" because Person is defined in this package
}
Now let's take a look at a struct with a method:
package main
import "fmt"
// A Person has qualities of a human
type Person struct {
first string
last string
}
// GetFirstName returns the first name of a person
func (p *Person) GetFirstName() string { // methods are like functions but have a receiver: (p *Person)
return p.first
}
func main() {
p := &Person{
first: "Ada",
last: "Lovelace",
}
fmt.Println(p.GetFirstName()) // We could still get the Person first name outside of this package because GetFirstName is public
}
Lastly, let's see what embedding a struct in another struct looks like:
package main
import "fmt"
// A Person has qualities of a human
type Person struct {
first string
last string
}
// GetFirstName returns the first name of a person
func (p *Person) GetFirstName() string {
return p.first
}
// An Athlete is a superset of a Person
type Athlete struct {
Person
sport string
}
func main() {
p := &Athlete{
Person: Person{
first: "LeBron",
last: "James",
},
sport: "basketball",
}
fmt.Println(p.GetFirstName()) // We do not have to access the Person sub-struct to call its methods
fmt.Println(p.Person.GetFirstName()) // We can explicitly reference the Person sub-struct and its methods
// Note: if Athlete had its own GetFirstName() method, then calling
// p.GetFirstName() would invoke it and p.Person.GetFirstName() would invoke
// the Person implementation.
}