Beginner · Collections and structs · topic 15 of 46 · 40 min
Structs and methods
Explanation
Why structs?
A student has a name, a roll number and marks. Keeping them in three separate variables, or three parallel slices, gets messy fast. A struct is a type that groups named fields, so one value holds the whole record.
type Student struct {
Name string
Roll int
Marks float64
}
func main() {
s := Student{Name: "Asha", Roll: 23, Marks: 91.5}
fmt.Println(s) // {Asha 23 91.5}
fmt.Printf("%+v\n", s) // {Name:Asha Roll:23 Marks:91.5}
fmt.Println(s.Name) // Asha
s.Marks = 93
var empty Student
fmt.Printf("%+v\n", empty) // {Name: Roll:0 Marks:0}
}Pointers to structs
Structs are values: assigning or passing one copies all its fields. To share one struct, use a pointer (the address of the value, covered fully in module 4). Go lets you use the dot directly on a pointer, without writing (*p).Name.
a := Student{Name: "Ravi", Marks: 70}
b := a // copy
b.Marks = 99
fmt.Println(a.Marks) // 70
p := &a // pointer to a
p.Marks = 80 // same as (*p).Marks = 80
fmt.Println(a.Marks) // 80
fmt.Println(p) // &{Ravi 0 80}Methods
A method is a function with a receiver: a special parameter written before the name. It lets you call s.Grade() instead of grade(s). You can define methods on any named type you declare in your package, not only structs.
func (s Student) Grade() string { // value receiver
if s.Marks >= 90 {
return "A"
}
return "B"
}
func (s *Student) AddGrace(n float64) { // pointer receiver
s.Marks += n
}
func main() {
st := Student{Name: "Meena", Marks: 88}
st.AddGrace(2) // Go passes &st automatically
fmt.Println(st.Marks, st.Grade()) // 90 A
}Value or pointer receiver?
| Use a pointer receiver (*T) when | A value receiver (T) is fine when |
|---|---|
| The method changes the receiver | The method only reads |
| The struct is large (copying is wasteful) | The type is small, like a Point or a Money amount |
| The struct contains a sync.Mutex or similar that must not be copied | The type is a basic type such as type Celsius float64 |
| Other methods of the type already use pointers (be consistent) | You want the value to behave like an immutable value |
Constructor functions
Go has no constructors. By convention you write a function named NewSomething that checks the inputs and returns a ready value, often a pointer.
type Account struct {
Holder string
balance int64 // lowercase: hidden outside the package
}
func NewAccount(holder string) (*Account, error) {
if holder == "" {
return nil, errors.New("holder name required")
}
return &Account{Holder: holder}, nil
}
func (a *Account) Deposit(paise int64) { a.balance += paise }
func (a *Account) Balance() int64 { return a.balance }Embedding: reuse without inheritance
Go has no inheritance. Instead you can embed one struct type inside another by writing just the type name as a field. The embedded type's fields and methods are promoted: you can use them directly on the outer struct. This is composition: an Employee HAS a Person, it is not a kind of Person.
type Person struct {
Name string
}
func (p Person) Hello() string { return "Namaste, " + p.Name }
type Employee struct {
Person // embedded
EmpID string
Salary int
}
func main() {
e := Employee{Person: Person{Name: "Kiran"}, EmpID: "E42"}
fmt.Println(e.Name) // Kiran (promoted field)
fmt.Println(e.Hello()) // Namaste, Kiran (promoted method)
}Comparing structs and struct tags
Two structs of the same type can be compared with == if all their fields are comparable (no slices or maps). A struct tag is a small text label after a field in backticks. Packages like encoding/json read tags to know the JSON name of a field. You will use them in module 7.
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price int `json:"price_paise"`
}Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Structs and methods · 1/7
Structs group related fields into one type, like a student record.
Prefer a video by a teacher? Find free videos on “golang structs methods pointer receiver vs value receiver embedding” on YouTube ↗
In real life: A bank account with rules
A wallet app models each account as a struct. The balance field is lowercase, so no other package can set it directly; money only moves through Deposit and Withdraw methods that check the rules, such as "you cannot withdraw more than the balance". This is how Go code protects important data without classes.
package main
import (
"errors"
"fmt"
)
type Wallet struct {
Owner string
balance int64 // paise
}
func (w *Wallet) Deposit(p int64) { w.balance += p }
func (w *Wallet) Withdraw(p int64) error {
if p > w.balance {
return errors.New("insufficient balance")
}
w.balance -= p
return nil
}
func (w Wallet) String() string {
return fmt.Sprintf("%s: Rs %d.%02d", w.Owner, w.balance/100, w.balance%100)
}
func main() {
w := &Wallet{Owner: "Asha"}
w.Deposit(50000)
if err := w.Withdraw(70000); err != nil {
fmt.Println("error:", err)
}
_ = w.Withdraw(12550)
fmt.Println(w) // Asha: Rs 374.50
}Practice (0/4 done)
What does this print? type P struct{ Name string; Age int } fmt.Printf("%+v", P{"Asha", 21})
What does this print? type C struct{ n int } func (c C) Inc() { c.n++ } ... x := C{} x.Inc() x.Inc() fmt.Println(x.n)
type Animal struct{ Name string }; type Dog struct{ Animal; Breed string }. d := Dog{Animal{"Moti"}, "Indie"}. What is d.Name?
Define type Rectangle struct with Width and Height (float64). Add a value-receiver method Area() float64 and a pointer-receiver method Scale(f float64) that multiplies both sides. Show that Scale changes the rectangle.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Strings, bytes and runesCollections and structs · same module
- StructsC Programming (from zero to systems) · Structs, unions, enums and files
- Structs: your own data typesRust Programming · Structs, enums and pattern matching
- Pointers to structs and the arrow operatorC Programming (from zero to systems) · Structs, unions, enums and files
- Structs, value types and reference typesC# and .NET · Classes and objects
- Pointers without fearPointers, interfaces and errors
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What does assigning one struct variable to another do?
Answer: Copies all the fields
Structs are values; assignment copies every field.
When should a method use a pointer receiver?
Answer: When it must change the receiver or the struct is large
Pointer receivers let methods modify the original and avoid copying big structs.
How does Go reuse code from another struct type?
Answer: Embedding (composition)
Embedding promotes the inner type's fields and methods to the outer type.
What does a field named balance (lowercase) mean?
Answer: It cannot be accessed from other packages
Lowercase identifiers are unexported: visible only inside their own package.
What is the Go convention for a constructor?
Answer: A function named NewTypeName
Go uses plain functions like NewAccount that return a ready value.
Can you assign one struct to another of the same type with =?Related
After let b = Student { roll: 2, ..a }; where a has String fields, what is true?Related
Answer: a's String fields were moved into b
Struct update syntax moves non-Copy fields.
Can a struct contain a member of its own struct type (not a pointer)?Related
Answer: No: it would be infinitely large; it can contain a pointer to its type
Self-reference must be through a pointer.
When is a struct a good choice?Related
Answer: For small, immutable, value-like data such as a point or money
Small, immutable values are the classic struct use.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- This is the last topic of “Collections and structs”. The module exam comes next.
- Module 3 exam: Collections and structs · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Pointers, interfaces and errors. 46 topics left in the course before the final exam.