0
0
Goprogramming~15 mins

Struct pointers in Go - Deep Dive

Choose your learning style9 modes available
Overview - Struct pointers
What is it?
Struct pointers in Go are variables that hold the memory address of a struct instead of the struct itself. This means you can access or modify the original struct data through the pointer without copying the entire struct. Using struct pointers helps manage memory efficiently and allows functions to change the struct's content directly.
Why it matters
Without struct pointers, every time you pass a struct to a function or assign it to another variable, Go copies the entire struct. This can be slow and waste memory, especially for large structs. Struct pointers solve this by letting you work with the original data directly, making programs faster and more memory-friendly.
Where it fits
Before learning struct pointers, you should understand basic structs and variables in Go. After mastering struct pointers, you can learn about methods with pointer receivers, interfaces, and memory management in Go.
Mental Model
Core Idea
A struct pointer is like a remote control that points to the original struct, letting you change or access it without carrying the whole thing around.
Think of it like...
Imagine a house (struct) and a mailbox key (pointer). Instead of carrying the whole house to a friend, you give them the key so they can enter and change things inside the house directly.
Struct value: [ Struct { field1, field2 } ]
Pointer:      [ *Struct ] ---> points to the struct's memory location

Access via pointer:
Pointer.field1  (accesses original struct's field1)

Memory:
[Pointer variable] --(holds address)--> [Struct data in memory]
Build-Up - 7 Steps
1
FoundationUnderstanding basic structs
πŸ€”
Concept: Learn what structs are and how to create and use them in Go.
A struct is a collection of fields grouped together. For example: ```go type Person struct { Name string Age int } func main() { p := Person{Name: "Alice", Age: 30} fmt.Println(p.Name, p.Age) } ``` This creates a Person struct and prints its fields.
Result
Output: Alice 30
Knowing structs is essential because pointers will refer to these grouped data structures.
2
FoundationWhat is a pointer in Go?
πŸ€”
Concept: Understand pointers as variables that store memory addresses.
A pointer holds the address of a variable. For example: ```go var x int = 10 var p *int = &x fmt.Println(*p) // prints 10 ``` Here, p points to x, and *p accesses x's value.
Result
Output: 10
Pointers let you access or change the original variable without copying it.
3
IntermediateCreating and using struct pointers
πŸ€”Before reading on: do you think you can use a pointer to access struct fields with the dot (.) operator directly? Commit to your answer.
Concept: Learn how to declare pointers to structs and access their fields.
You can create a pointer to a struct using the & operator: ```go type Person struct { Name string Age int } func main() { p := Person{Name: "Bob", Age: 25} ptr := &p fmt.Println(ptr.Name) // Access field via pointer ptr.Age = 26 // Modify field via pointer fmt.Println(p.Age) // Shows updated value } ``` Go lets you use the dot operator on pointers to structs directly.
Result
Output: Bob 26
Understanding that Go automatically dereferences struct pointers when accessing fields simplifies working with pointers.
4
IntermediatePassing struct pointers to functions
πŸ€”Before reading on: do you think passing a struct pointer to a function allows the function to modify the original struct? Commit to your answer.
Concept: Learn how passing pointers to functions lets them modify the original struct.
When you pass a struct pointer to a function, the function can change the original struct: ```go type Person struct { Name string Age int } func birthday(p *Person) { p.Age++ } func main() { p := Person{Name: "Carol", Age: 40} birthday(&p) fmt.Println(p.Age) // 41 } ``` The function receives the address and updates the struct directly.
Result
Output: 41
Knowing this prevents unnecessary copying and enables efficient updates to data.
5
IntermediateNil struct pointers and safety
πŸ€”Before reading on: do you think accessing fields through a nil struct pointer causes a runtime error? Commit to your answer.
Concept: Understand that nil pointers to structs cause errors if dereferenced and how to check for nil.
A struct pointer can be nil, meaning it points to nothing: ```go var p *Person = nil fmt.Println(p.Name) // panic: runtime error ``` To avoid this, check for nil before accessing: ```go if p != nil { fmt.Println(p.Name) } else { fmt.Println("Pointer is nil") } ```
Result
Output: Pointer is nil
Recognizing nil pointers helps avoid crashes and write safer code.
6
AdvancedPointer receivers in methods
πŸ€”Before reading on: do you think methods with pointer receivers can modify the struct's fields? Commit to your answer.
Concept: Learn how methods can use pointer receivers to modify the original struct.
Methods can have pointer receivers to change the struct: ```go type Person struct { Name string Age int } func (p *Person) HaveBirthday() { p.Age++ } func main() { p := Person{Name: "Dave", Age: 50} p.HaveBirthday() fmt.Println(p.Age) // 51 } ``` Using pointer receivers avoids copying the struct on method calls.
Result
Output: 51
Understanding pointer receivers is key to writing efficient and correct methods that modify structs.
7
ExpertSubtle pointer aliasing and mutation traps
πŸ€”Before reading on: do you think two pointers to the same struct always behave independently? Commit to your answer.
Concept: Explore how multiple pointers to the same struct can cause unexpected side effects when mutated.
If you have multiple pointers to the same struct, changing the struct via one pointer affects all: ```go p1 := &Person{Name: "Eve", Age: 20} p2 := p1 p2.Age = 21 fmt.Println(p1.Age) // 21 ``` This aliasing can cause bugs if you expect independent copies. To avoid this, explicitly copy structs when needed: ```go p3 := *p1 // copy struct value p3.Age = 22 fmt.Println(p1.Age) // still 21 ```
Result
Output: 21 21
Knowing pointer aliasing helps prevent subtle bugs from unintended shared mutations in complex programs.
Under the Hood
Struct pointers store the memory address where the struct's data lives. When you use a pointer to access or modify fields, Go automatically dereferences the pointer to reach the actual data in memory. This avoids copying the entire struct. Internally, the pointer is just a number representing the location in memory, and the Go runtime uses this to read or write the struct's fields directly.
Why designed this way?
Go was designed for simplicity and efficiency. Using pointers to structs avoids expensive copying of large data structures and allows functions and methods to modify data directly. The language automatically dereferences pointers to structs to keep syntax clean and easy to read, unlike some languages where explicit dereferencing is required. This design balances performance with developer friendliness.
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Pointer var   │──────▢│ Struct in     β”‚
β”‚ (memory addr) β”‚       β”‚ memory block  β”‚
β”‚               β”‚       β”‚ { fields... } β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Access flow:
Pointer.var.field  ==  *(Pointer.var).field

Memory:
[Pointer variable] stores address --> Go runtime uses address to access struct fields
Myth Busters - 4 Common Misconceptions
Quick: Does using a struct pointer always make your program faster? Commit to yes or no.
Common Belief:Using struct pointers always improves performance because it avoids copying.
Tap to reveal reality
Reality:While pointers avoid copying, overusing them can cause cache misses and make code harder to understand, sometimes reducing performance.
Why it matters:Blindly using pointers everywhere can lead to slower programs and bugs, so knowing when to use them is crucial.
Quick: Can you use the dot operator directly on a struct pointer without explicit dereferencing? Commit to yes or no.
Common Belief:You must always use * to dereference a struct pointer before accessing its fields.
Tap to reveal reality
Reality:Go automatically dereferences struct pointers when you use the dot operator, so explicit * is not needed.
Why it matters:Misunderstanding this leads to verbose and confusing code, missing Go's simplicity.
Quick: If you copy a struct pointer, do you get a new independent struct? Commit to yes or no.
Common Belief:Copying a struct pointer creates a new struct copy independent of the original.
Tap to reveal reality
Reality:Copying a pointer copies the address only; both pointers refer to the same struct in memory.
Why it matters:Assuming independence causes bugs when changes via one pointer unexpectedly affect the other.
Quick: Is it safe to dereference a nil struct pointer without checks? Commit to yes or no.
Common Belief:Dereferencing a nil struct pointer is safe and returns zero values.
Tap to reveal reality
Reality:Dereferencing a nil pointer causes a runtime panic (crash).
Why it matters:Ignoring nil checks leads to program crashes and poor user experience.
Expert Zone
1
Pointer receivers in methods not only avoid copying but also enable method chaining and interface implementations that require pointer semantics.
2
Using struct pointers affects garbage collection behavior because pointers keep the referenced struct alive; careless use can cause memory leaks.
3
The Go compiler optimizes some struct copies away, so sometimes using pointers is unnecessary for small structs, balancing readability and performance.
When NOT to use
Avoid struct pointers when working with small structs that are cheap to copy or when you want to ensure data immutability. Instead, pass structs by value to prevent accidental mutations. Also, avoid pointers in concurrent code without synchronization to prevent race conditions.
Production Patterns
In real-world Go code, struct pointers are used extensively in methods to modify objects, in APIs to reduce copying large data, and in data structures like linked lists or trees where nodes reference each other. Idiomatic Go code uses pointer receivers for mutable structs and value receivers for immutable ones.
Connections
References in C++
Similar concept of referring to existing data without copying, but Go pointers require explicit dereferencing in C++.
Understanding Go struct pointers helps grasp how languages manage memory references differently, improving cross-language skills.
Memory addresses in computer architecture
Struct pointers directly relate to how computers use memory addresses to locate data.
Knowing struct pointers deepens understanding of how programs interact with hardware memory, bridging software and hardware knowledge.
Pointers in biology (DNA pointers)
Like pointers in Go, DNA sequences contain pointers to specific genes or instructions that affect the organism.
Seeing pointers as references to original data helps connect programming concepts to biological information storage and retrieval.
Common Pitfalls
#1Dereferencing a nil struct pointer causing a crash.
Wrong approach:var p *Person fmt.Println(p.Name) // panic: runtime error
Correct approach:var p *Person if p != nil { fmt.Println(p.Name) } else { fmt.Println("Pointer is nil") }
Root cause:Not checking if the pointer is nil before accessing its fields.
#2Assuming copying a pointer copies the struct data.
Wrong approach:p1 := &Person{Name: "Ann", Age: 30} p2 := p1 p2.Age = 31 fmt.Println(p1.Age) // expects 30 but prints 31
Correct approach:p1 := &Person{Name: "Ann", Age: 30} p2 := *p1 // copy struct value p2.Age = 31 fmt.Println(p1.Age) // prints 30
Root cause:Confusing pointer copy with struct copy; pointers share the same data.
#3Using struct pointers unnecessarily for small structs.
Wrong approach:func printPerson(p *Person) { fmt.Println(p.Name) } // called with &Person{Name: "Tom"}
Correct approach:func printPerson(p Person) { fmt.Println(p.Name) } // called with Person{Name: "Tom"}
Root cause:Overusing pointers when copying small structs is cheap and clearer.
Key Takeaways
Struct pointers hold the address of a struct, allowing direct access and modification without copying the whole struct.
Go automatically dereferences struct pointers when accessing fields, making syntax simple and clean.
Passing struct pointers to functions or methods enables efficient updates to the original data.
Nil struct pointers must be checked before use to avoid runtime crashes.
Understanding pointer aliasing is crucial to prevent bugs from unintended shared mutations.