Go Structs, Methods and Interfaces
Go has no classes. Instead it uses structs for data, methods for actions, and interfaces for shared behaviour.
Structs
A struct groups related fields under one name:
Example
package main
import "fmt"
type Student struct {
Name string
Age int
Marks int
}
func main() {
s1 := Student{Name: "Ali", Age: 19, Marks: 82}
s2 := Student{"Ayesha", 20, 91}
fmt.Println(s1.Name, s1.Marks)
s2.Marks = 95
fmt.Println(s2)
fmt.Printf("%+v\n", s1)
}Ali 82
{Ayesha 20 95}
{Name:Ali Age:19 Marks:82}%+v prints the field names too, which helps when debugging.
Field names that start with a capital letter are visible to other packages. Lowercase names stay private to their package.
Methods
A method is a function attached to a type. The receiver appears in brackets before the method name.
Example
package main
import "fmt"
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r *Rectangle) Scale(f float64) {
r.Width *= f
r.Height *= f
}
func main() {
room := Rectangle{Width: 10, Height: 12}
fmt.Println(room.Area())
room.Scale(2)
fmt.Println(room.Width, room.Height, room.Area())
}120 20 24 480
| Receiver | Example | Use it when |
|---|---|---|
| Value | (r Rectangle) | The method only reads the data |
| Pointer | (r *Rectangle) | The method changes the data |
A value receiver works on a copy, so changes would be lost. That is why Scale uses a pointer.
Pointers in Short
A pointer holds the address of a value. &x gives the address, and *p reads the value at that address.
Example
package main
import "fmt"
func addBonus(marks *int) {
*marks += 5
}
func main() {
m := 70
addBonus(&m)
fmt.Println(m)
}75
Interfaces
An interface lists method signatures. Any type that has those methods automatically satisfies the interface. There is no implements keyword.
Example
package main
import "fmt"
type Payment interface {
Pay(amount int) string
}
type Cash struct{}
type Card struct {
Bank string
}
func (c Cash) Pay(amount int) string {
return fmt.Sprintf("Paid Rs %d in cash", amount)
}
func (c Card) Pay(amount int) string {
return fmt.Sprintf("Paid Rs %d with %s card", amount, c.Bank)
}
func checkout(p Payment, amount int) {
fmt.Println(p.Pay(amount))
}
func main() {
checkout(Cash{}, 500)
checkout(Card{Bank: "Meezan"}, 1200)
}Paid Rs 500 in cash Paid Rs 1200 with Meezan card
checkout works with any payment type. You can add a new type later, such as a mobile wallet, without changing checkout.
Embedding
A struct can include another struct. Its fields and methods become available directly:
Example
type Person struct{ Name string }
type Teacher struct {
Person
Subject string
}With t := Teacher{Person{"Sir Imran"}, "Maths"}, you can write t.Name directly.
Exercise
Exercise
How does a type satisfy an interface in Go?
