Pointers to Structs
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 20 of 107.
When working with structs, you'll often use pointers to avoid copying large data structures and to modify the original struct. A pointer to a struct holds the memory address of that struct instance.
You can create a struct pointer using the & operator on an existing struct, or by using the address operator directly with a struct literal.
type Person struct {
Name string
Age int
}
p := Person{Name: "Alice", Age: 30}
ptr := &p // pointer to existing struct
// Or create directly
ptr2 := &Person{Name: "Bob", Age: 25}Go provides a convenient shortcut when accessing struct fields through a pointer. Instead of writing (*ptr).Name, you can simply write ptr.Name. Go automatically dereferences the pointer for you.
ptr := &Person{Name: "Alice", Age: 30}
// Both work identically
fmt.Println((*ptr).Name) // explicit dereference
fmt.Println(ptr.Name) // automatic dereferenceThis automatic dereferencing also applies when modifying fields. Changes through the pointer affect the original struct.
p := Person{Name: "Alice", Age: 30}
ptr := &p
ptr.Age = 31 // modifies original
fmt.Println(p.Age) // 31Struct pointers are essential in Go's OOP patterns. They enable methods to modify receiver state, allow efficient passing of large structs to functions, and form the foundation for building linked data structures like trees and lists.
Challenge
EasyLet's build a bank account system that demonstrates how struct pointers allow you to modify the original data efficiently. You'll create an account that can be updated through pointer operations.
You'll organize your code across two files:
account.go: Define aBankAccountstruct withOwner(string),Balance(float64), andAccountNumber(string) fields. Create a function calledNewAccountthat takes an owner name and account number as parameters and returns a pointer to a newBankAccountwith a starting balance of 0. Also create aDepositfunction that takes a*BankAccountpointer and an amount, then adds that amount to the account's balance through the pointer.main.go: Read account information from input, create an account using your constructor function (which returns a pointer), make a deposit using the pointer, and display the account details to confirm the balance was modified.
The following inputs will be provided:
- Line 1: Owner name
- Line 2: Account number
- Line 3: Deposit amount (float)
Output format:
Account: [AccountNumber]
Owner: [Owner]
Balance: [Balance]For example, given John Smith, ACC-12345, and 500.50, your output should be:
Account: ACC-12345
Owner: John Smith
Balance: 500.50Remember that your NewAccount function should return *BankAccount using the & operator, and your Deposit function can modify the balance directly through the pointer using Go's automatic dereferencing (e.g., account.Balance instead of (*account).Balance).
Cheat sheet
A pointer to a struct holds the memory address of a struct instance. Create struct pointers using the & operator:
type Person struct {
Name string
Age int
}
p := Person{Name: "Alice", Age: 30}
ptr := &p // pointer to existing struct
// Or create directly
ptr2 := &Person{Name: "Bob", Age: 25}Go provides automatic dereferencing when accessing struct fields through a pointer. Instead of (*ptr).Name, you can write ptr.Name:
ptr := &Person{Name: "Alice", Age: 30}
// Both work identically
fmt.Println((*ptr).Name) // explicit dereference
fmt.Println(ptr.Name) // automatic dereferenceChanges through a pointer affect the original struct:
p := Person{Name: "Alice", Age: 30}
ptr := &p
ptr.Age = 31 // modifies original
fmt.Println(p.Age) // 31Struct pointers enable methods to modify receiver state, allow efficient passing of large structs to functions, and form the foundation for linked data structures.
Try it yourself
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Read owner name
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// Read account number
accountNumber, _ := reader.ReadString('\n')
accountNumber = strings.TrimSpace(accountNumber)
// Read deposit amount
amountStr, _ := reader.ReadString('\n')
amountStr = strings.TrimSpace(amountStr)
amount, _ := strconv.ParseFloat(amountStr, 64)
// TODO: Create a new account using NewAccount function (returns a pointer)
// TODO: Make a deposit using the Deposit function with the account pointer
// TODO: Print the account details in the required format:
// Account: [AccountNumber]
// Owner: [Owner]
// Balance: [Balance]
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool