Pointers¶
Pointers are mainly used to access variables directly inside functions.
Similar to C, but not as complicated as pointers in C.
Starting with this example; reading user input to get their name.
fmt.Println("What is your name? ${white}")
var name string
fmt.Scanln(&name) // This is the memory address (a pointer)
// This is passing-by-reference.
fmt.Scanln reads from standard input (user input on the CLI).It stops reading at newline (
<CR>) or end of file.
Since fmt.Scanln needs to modify the value of the name variable, the only way
to do this is to pass a Pointer to the function - its memory address (&name).
&namepasses the memory address of thenamevariable (a pointer) tofmt.Scanln.fmt.Scanlndereferences the pointer (accesses the value stored at the memory address) and modifies the actualnamevariable.
Why a pointer is needed here:
fmt.Scanlnneeds to assign the user input to thenamevariab.e- Without passing its address,
fmt.Scanlnwould only work with a copy ofnameand wouldn't be able to modify the original variable.
So, if you need to pass a variable to a function in order to modify its value, use a pointer.
Example: Using a pointer to modify a variable directly¶
package main
import ("fmt")
func ChangeAge(age *int) newage int {
*age = newage
}
func main() {
var age int = 30
fmt.Println("Your age:", age)
ChangeAge(&age, 33)
fmt.Printf("New age: %v\n", age)
}
If you called ChangeAge without referencing &age, it would only pass the value
of age (30).
Pointer Receivers in Functions (Methods)¶
When creating methods for structs, you can use Pointer Receivers to modify the actual struct itself.
Ex: Task list project I'm working on:
package tasks
// this is in ./internal/tasks/tasks.go
type Task struct {
Title string,
Description string,
Completed bool
}
type TaskList struct {
Tasks []Task
}
// Create some methods for the new objects
// Use a pointer receiver to access the variable itself
func (tl *TaskList) AddTask(title string, desc string) {
newTask := Task{
Title: title,
Description: desc,
Completed: false,
}
tl.Tasks = append(tl.Tasks, newTask)
}
This uses func (tl *TaskList), which is called a receiver.
A receiver is used to associate a method with a type.
The receiver defines it as a method for the type TaskList.
It uses the * in front of TaskList so that it can access the variable itself,
making this a pointer receiver.
When using a pointer receiver, any changes made to tl (the TaskList object)
inside the method affects the original object instead of a copy.
This method can be called directly without explicitly passing a pointer.
E.g.,