实验

1
2
3
4
func (engine *Engine) Delims(left, right string) *Engine {
engine.delims = render.Delims{Left: left, Right: right}
return engine
}

golang中,一个方法的接收者可以为指针或者非指针,那么这两种形式的区别是什么呢?

这里做了个实验

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
package main

import "fmt"

type Test struct {
a int
b int
}

func (h Test) testA() {
(*h).b = 666
}

func (h *Test) testB() {
h.b = 999
}

func main() {
t := Test{a: 1, b: 2}
t.testA()

fmt.Println(t)
t.testB()
fmt.Println(t)
}

输出:

1
2
{1 2}
{1 999}

可以发现:当接收者为指针时,我们可以通过方法改变该接收者的属性,非指针类型不能改变接收者属性

补充

对于切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

type Heap []int

func (h Heap) testA() {
h[1] = 666
}

func (h *Heap) testB() {
(*h)[1] = 999
}

func main() {
heap := Heap{1, 2, 3, 4}

heap.testA()
fmt.Println(heap)

heap.testB()
fmt.Println(heap)
}

当接收者为一个切片时,输出是什么呢?结果如下

1
2
[1 666 3 4]
[1 999 3 4]

可以发现,这里testA仍然改变了切片的属性。

原因与golang中切片的底层有关

切片的底层

一个切片是一个数组片段的描述。它包含了指向数组的指针,片段的长度, 和容量(片段的最大长度)。

可以发现,当传递切片本身就是用一个指针来引用指向的数组,所以可以使用这种方法改变切片的属性。

对于数组

当我们把Heap类型改为数组时,可以发现结果又和当初的结构体差不多了,即接收者为非指针时不能更改值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import "fmt"

type Heap [4]int

func (h Heap) testA() {
h[1] = 666
}

func (h *Heap) testB() {
(*h)[1] = 999
}

func main() {
heap := Heap{1, 2, 3, 4}

heap.testA()
fmt.Println(heap)

heap.testB()
fmt.Println(heap)
}

输出:

1
2
[1 2 3 4]
[1 999 3 4]