Pointer Indirection
Introduction
Indirection in Go means accessing values through a pointer rather than directly, enabling functions to use variables as references
instead of copies of value. It is quite similar to the concept of reference in C++
.
In Functions
Functions with pointer indirection can be declared as:
func ScaleFunc(v *Vertex, f float64) {
v.X *= f
v.Y *= f
}
And the function call is:
v := Vertex{3, 4}
ScaleFunc(&v, 10)
// Or
p := &Vertex{4, 3}
ScaleFunc(p, 8)
It looks like C/C++
, where &
is used to gain the address of variables, and *
is used to get the value from an address.
In Methods
Since Go
is not a traditionally object-oriented language. It does allow programmers to create methods for a structure. And the form of calling a method is similar to C++
, which uses .
to access the method function or member function.
However, there is no this
concept in method functions, meaning that calling method functions copies values.
For example, here is a structure named Vertex
.
type Vertex struct {
X, Y float64
}
And to declare a function as its method, it can be written as:
func (v Vertex) Show() {
fmt.Println(v.X, v.Y)
}
Then the function can be used as v.Show()
.
However, if we want to change the value inside the structure, like scaling the vertex, this approach will not work.
func (v Vertex) FakeScale(f float64) {
v.X *= f
v.Y *= f
}
func main() {
SCALE_FACTOR := 10
v := Vertex{3, 4}
v.FakeScale(float64(SCALE_FACTOR))
v.Show()
}
The output of above code is 3 4
, so the scale operation is failed. It demonstrates that this method function use v
as a copy of value, rather than itself or a reference.
To achieve the goal, the following code will work.
func (v *Vertex) Scale(f float64) {
v.X *= f
v.Y *= f
}
It uses v
as a reference so that the function can modify its values.
func (v *Vertex) Scale(f float64) {
v.X *= f
v.Y *= f
}
func main() {
SCALE_FACTOR := 10
v := Vertex{3, 4}
v.Scale(float64(SCALE_FACTOR))
v.Show()
}
The code above will output 30 40
as expectation.
In addition, if there is a pointer of Vertex
, then it can also call this function.
func (v *Vertex) Scale(f float64) {
v.X *= f
v.Y *= f
}
func main() {
SCALE_FACTOR := 10
v := &Vertex{3, 4}
v.Scale(float64(SCALE_FACTOR))
v.Show()
}
Since Scale()
function has a pointer receiver, it allows a pointer variable (v
in the above code) to call itself.
In fact, in the previous example, Go
interprets v.Scale()
as (&v).Scale()
, so it can use the method function with pointer receiver.