Pointer vs Value Receivers
Part of the Object Oriented Programming section of Coddy's GO journey. Lesson 8 of 107.
Methods can have either a value receiver or a pointer receiver. A value receiver works on a copy of the struct. A pointer receiver works on the original struct and can modify its fields.
Value receiver: works on a copy
type Counter struct {
Count int
}
func (c Counter) GetCount() int {
return c.Count
}
// This does NOT modify the original
func (c Counter) IncrementWrong() {
c.Count++ // Only changes the copy!
}Pointer receiver: modifies the original
// This DOES modify the original
func (c *Counter) Increment() {
c.Count++
}
func (c *Counter) Reset() {
c.Count = 0
}Using both together
func main() {
counter := Counter{Count: 0}
counter.Increment()
counter.Increment()
fmt.Println(counter.GetCount()) // Output: 2
counter.Reset()
fmt.Println(counter.GetCount()) // Output: 0
}Use a value receiver when the method only reads data. Use a pointer receiver (*StructName) when the method needs to modify the struct's fields. Go automatically handles the referencing. You call both the same way.
Challenge
MediumAdd methods to the Wallet struct using the correct receiver types:
GetBalance: value receiver, returns the current balanceDeposit: pointer receiver, adds amount to balanceWithdraw: pointer receiver, subtracts amount only if sufficient funds
Try it yourself
package main
import "fmt"
func main() {
var balance, deposit, withdraw float64
fmt.Scan(&balance, &deposit, &withdraw)
w := Wallet{Balance: balance}
fmt.Printf("Balance: %.2f\n", w.GetBalance())
w.Deposit(deposit)
fmt.Printf("After deposit: %.2f\n", w.GetBalance())
w.Withdraw(withdraw)
fmt.Printf("After withdrawal: %.2f\n", w.GetBalance())
fmt.Printf("Final balance: %.2f\n", w.GetBalance())
}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 PoolPractice on your own: Online Go compiler