Go 指针接收者
2024-09-02 15:15:42 # Go

Go 语言中可以对方法声明接收者,接收者类型可以是结构体也可以是接口。这意味着被声明的方法只能被该结构体或者是接口的实例调用。

语法如下:

1
2
3
func (t Type) methodMame(params) returns {
// method body
}

特别地,在此处可以声明指针接收者,语法如下:

1
2
3
func (t *Type) methodMame(params) returns {
// method body
}

A tour of Go 中介绍到

You can declare methods with pointer receivers.
// 你可以为方法绑定一个指针接收者

This means the receiver type has the literal syntax *T for some type T. (Also, T cannot itself be a pointer such as *int.)
// 这意味着接收者类型是 T 的指针,其中 T 不能是像 *int 这样的指针类型。

他的作用也很简单,就是可以修改接收者指向的值。如果没有使用指针接收者,那么修改的只是接收者的一个副本,并不影响原来的值。

从字面语义上也很直观,我们通常理解的指针就是指向变量的地址,对指针的操作会影响原来的变量值。

实例

举例来说,声明一个结构体Vertex,为Vertex绑定方法AbsScaleShrink,其中AbsShrink方法使用值接收者,Scale方法使用指针接收者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 (v Vertex) Shrink(f float64) {
if f == 0 {
return
}
v.X = v.X / 10
v.Y = v.Y / 10
}

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

输出的结果为:

1
2
3
5
50
50

可以看到,AbsShrink方法使用值接收者,所以AbsShrink方法内部对v的修改不会影响原来的v

Scale方法使用指针接收者,所以Scale方法内部对v的修改会影响原来的v

如果将Shrink方法的接收者类型改为指针接收者:

1
2
3
4
5
6
7
func (v *Vertex) Shrink(f float64) {
if f == 0 {
return
}
v.X = v.X / 10
v.Y = v.Y / 10
}

结果为:

1
2
3
5
50
5