A pointer is simply a variable that holds the location in memory where a value is stored.
Pointer indicates mutable parameter.
Go gives the choice to use pointers or values for both primitives and structs.
The common gotcha is when passing a struct - a struct is passed by value. Example
func changePersonFailed(person Person){
person.Name = "Jane"
}
person := Person{Name: "John", Age: 1}
changePersonFailed(person)
Original person object is not modified since the person is a copy of the original person struct
To pass by reference or in other words, passing the pointer instead, can be done by adding the * prefix on the person parameter in the method definition, and to pass the pointer of the object by adding & prefix to the person object
func changePerson(person *Person){
person.Name = "Jane"
desc := "new value"
person.Description = &desc
}
person := Person{Name: "John", Age: 1}
changePerson(&person)
The best practice, however, is to always strive to not modify the object passed as argument into the function and return it as a return value of the function instead, such as:
func changePersonBestPractice(person Person) (p Person) {
p = Person{Name: "Name", Age: person.Age}
return p
}
person := Person{Name: "John", Age: 1}
updatedPerson := changePersonBestPractice(person)
Mutated object can be difficult to track of - where the object was mutated . Instead, returning a new object will guarantee the original object is modified while still getting back a new object with updated values.
append methods is an example of this practice. Original slice is kept as is, and a new slice returned with the given element added
names := []string{"a","b"}
names = append(names, "c")
fmt.Println(names)
Another reason is garbage collector has more work with pointers since value types are in stack and stack is sequential where as heap where the pointers located are not.
Top comments (0)