Go tour - pointer receivers

228 阅读1分钟

If you'd like to modify the type value on some functions, please consider using pointer receiver as below

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func case1() {
	v := Vertex{3, 4}
	v.Scale(10)
	fmt.Println(v.Abs())
}

func main() {
	case1()
}

In above code,Abs and Scale are all pointer receiver functions.The output is 50, since when calling Scale method, if will change the original X and Y of v. In other word, after calling Scale,X will be changed from 3 to 30,and Y will be changed from 4 to 40. But if you remove the start mark before Vertex, the output is 5. The reason the now the Scale operation is performed on the copy of v.

Comparing with Abs and Scale in the form of pointer receiver, we rewrote Abs and Scale in the form of general function:

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

func Abs(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func Scale(v *Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func case1() {
	v := Vertex{3, 4}
	Scale(&v, 10)
	fmt.Println(Abs(v))
}

func main() {
	case1()
}

Please note in this form, since the v *Vertex is now as a argument in Scale method, when you call it, you must pass a pointer kind value as &v, the & operator is required.

If some type implements an interface ,and it's used as pointer receiver, it's required to pass a pointer to the client, see below code

package main

import (
	"fmt"
	"math"
)

type I interface {
	M()
}

type T struct {
	S string
}

func (t *T) M() {
	fmt.Println(t.S)
}

type F float64

func (f F) M() {
	fmt.Println(f)
}

func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}

func main() {
	var i I

	i = &T{"hello"}
	describe(i)
	i.M()

	i = F(math.Pi)
	describe(i)
	i.M()
}

t implements M method of interface, since it declared as a pointer type variable, so when assign itself to variable i, it's required in the form of pointer: i = &T{"hello"}