So far, when we've passed values to functions, Go has made copies of those values. But what if we want to work with the original value instead of a copy? That's where pointers come in.
When you pass a value to a function, Go creates a copy of that value:
func tryToChange(number int) {
number = 100
fmt.Println("Inside function:", number)
}
func main() {
myNumber := 42
tryToChange(myNumber)
fmt.Println("Outside function:", myNumber)
}
// Output:
// Inside function: 100
// Outside function: 42
Even though we changed number inside the function, myNumber in main remained unchanged. This is because the function received a copy.
A pointer is a variable that stores the memory address of another variable, rather than storing the value itself. Think of it like a street address - it tells you where to find something, rather than being the thing itself.
To work with pointers, you need two special operators:
The & operator (address-of): Gets the memory address of a variable
x := 42
ptr := &x // ptr now holds the address of x
The * operator (dereference): Accesses the value at a memory address
x := 42
ptr := &x
fmt.Println(*ptr) // Prints: 42 (the value at that address)
When declaring a pointer type, you put * before the type:
var numberPtr *int // Pointer to an int
var namePtr *string // Pointer to a string
var activePtr *bool // Pointer to a bool
func main() {
age := 30
// Get the address of age
agePtr := &age
fmt.Println("Value of age:", age) // Output: 30
fmt.Println("Address of age:", agePtr) // Output: 0x... (memory address)
fmt.Println("Value at address:", *agePtr) // Output: 30
}
When you have a pointer, you can modify the original value:
func main() {
score := 100
scorePtr := &score
*scorePtr = 200 // Change the value at the address
fmt.Println(score) // Output: 200 (original was modified!)
}
This is where pointers become really useful - you can pass a pointer to a function to modify the original value:
func addBonus(scorePtr *int) {
*scorePtr = *scorePtr + 50
}
func main() {
score := 100
fmt.Println("Before:", score) // Output: Before: 100
addBonus(&score)
fmt.Println("After:", score) // Output: After: 150
}
Notice:
*int (a pointer to an int)&score (the address of score)*scorePtr to access and modify the value// Without pointer - makes a copy
func doubleValue(n int) {
n = n * 2
fmt.Println("Inside:", n) // Changed
}
// With pointer - modifies original
func doublePointer(n *int) {
*n = *n * 2
fmt.Println("Inside:", *n) // Changed
}
func main() {
value := 10
doubleValue(value)
fmt.Println("Outside:" value
Use pointers when:
Don't use pointers when:
For this challenge, create a function called levelUp that accepts a pointer to an integer *int as a parameter.
The function should:
"Leveled up!"Then in your main function:
playerLevel with the value 5"Initial level: [playerLevel]"levelUp with the address of playerLevel"New level: [playerLevel]"