GO:值接收者和指针接收者的区别

GO:值接收者和指针接收者的区别

虽然我们之前提到过,在使用S.F()方式调用方法时,GO对值和指针的限制是宽松的,但是在继承接口这方面,这里是有着严格的区分的。

1. 实现接口的函数接收者全是值,使用值调用

type I interface {
	M()
	M2()
}

type S struct {
	number int64
}

func (s S) M() {
	fmt.Println(s.number)
}

func (s S) M2() {
	fmt.Println(s.number)
}

func F(i I) {
	i.M()
	i.M2()
}

func main() {
	s := S{number: 64}
	F(s)
}

这里所有的M()函数接受者都是值,因此F(s)是没问题的

2. 实现接口的函数接收者部分是值,使用值调用

修改上面的函数定义:

func (s *S) M2() {
	fmt.Println(s.number)
}

这里的M2()接收者改成了指针,F(s)就不能调用了,因为S的值现在不算实现了I接口。

3. 实现接口的函数接收者全是指针,使用指针调用

这种情况显然是成立的,不贴代码了。

4. 实现接口的函数接收者部分是指针,使用指针调用

type I interface {
	M()
	M2()
}

type S struct {
	number int64
}

func (s S) M() {
	fmt.Println(s.number)
}

func (s *S) M2() {
	fmt.Println(s.number)
}

func F(i I) {
	i.M()
	i.M2()
}

func main() {
	s := &S{number: 64}
	F(s)
}

这里也是能正常调用的。

5. 实现接口的函数接收者全是值,使用指针调用

type I interface {
	M()
	M2()
}

type S struct {
	number int64
}

func (s S) M() {
	fmt.Println(s.number)
}

func (s S) M2() {
	fmt.Println(s.number)
}

func F(i I) {
	i.M()
	i.M2()
}

func main() {
	s := &S{number: 64}
	F(s)
}

这里依然能够正常调用。


总结

综上所述,在没有特殊要求的情况下,统一使用指针作为接收者是最好的选择。
我们也可以发现:

  1. 使用S.F()的方式调用,解引用和取地址都是自动进行的
  2. 使用F(S)的方式调用,能够自动解引用,但是不能自动取地址
posted @ 2024-12-22 13:22  Gold_stein  阅读(93)  评论(0)    收藏  举报