go 结构体方法的困惑

2021-03-23 21:15:33 +08:00
 yujianwjj
type A struct {
	i int
}

func (a *A) Set(i int) {
	a.i = i
}

func TestInherit(t *testing.T) {
	var a = A{3}
	a.Set(4)
    t.Log(a.i)  // 输出 4
}

这里可以通过非指针的 a 调用 Set 函数,并且 Set 的值是有效地。

第一个疑问:go 在调用方法时,会先将接收器的值复制一份,然后在这个副本上执行方法。我的理解是 a 复制了一份,在新的 a 上面修改不应该影响原来的 a 。

type Set interface {
	Set(int)
}

type A struct {
	i int
}

func (a *A) Set(i int) {
	a.i = i
}

func TestInherit(t *testing.T) {
	var _ Set = A{}		// 这里编译不通过,提示没有实现 Set 方法。
}

第二个疑问,为啥上面的例子能调用 a.Set(),为啥这里又报错说没有实现 Set 方法。

2740 次点击
所在节点    Go 编程语言
12 条回复
SuperMild
2021-03-23 21:38:13 +08:00
https://tour.golang.org/methods/6

That is, as a convenience, Go interprets the statement v.Scale(5) as (&v).Scale(5) since the Scale method has a pointer receiver.
thefack
2021-03-23 21:41:32 +08:00
第一个问题是编译器给你补充了引用:`&a.Set(4)`
第二个问题对照第一个问题,实现 Set 的是 &A,不是 A,所以报错
linvon
2021-03-23 21:43:15 +08:00
一:如果是值接收器确实是做一次值拷贝,但你这个方法是指针接收器,go 会对 a 做取地址,在执行指针接收器的方法,就会修改值
二:Set 方法实现的是指针接收器,A{}是一个值类型,并没有实现 Set 方法

可以去搜一下 go 的值接收器和指针接收器区别
kiripeng
2021-03-23 21:52:40 +08:00
type A struct {
i int
}

func (a *A) Set(i int) {
a.i = i
}

等于 func Set(a *A,i int) 这个准确来说是实现了指针形式的方法集
如果不用指针 var _ Set =&A{}而是使用 var _ Set =A{} 就会出现这个问题就是了,因为这时候是去 A 找实现了非地址值的方法集,然后找不到,可惜的是对于 golang 来说我觉得他限制了地址值和非地址值嵌入只能一种最大的目的应该是防止出现用到后面会出事,不知道哪个是哪个,防止地址值的方法集和非地址值的方法集混淆。
var _ Set =A{} 如果要行得通就是 func (a A) Set(i int) {
a.i = i
}

func (a *A) Set(i int) {
a.i = i
}
而对于这个,a.set 其实就是转化成 (&a,)了,这个你可以试下如果实现的是

func (a A) Set(i int) {
a.i = i
}
用空指针去调用他就会爆出
main.(*A).Set(...)
keepeye
2021-03-23 22:00:33 +08:00
第一个是值拷贝没错,但是调方法的时候隐式转换成指针接收了,但不能说 a 实现了 Set 接口。。所以还是代码不规范的问题,正常因该不会这么写
george404
2021-03-24 07:09:54 +08:00
试试看

```
func (a *A) Set(i int) {
a.i = i
}
```
改成

```
func (a *A) Set(i int) {
a.i = i
}
```
你看看你还能修改值了
love2020
2021-03-24 08:31:00 +08:00
为什么不先看教程。。。
liuxey
2021-03-24 08:40:21 +08:00
@froyobin #6 你这.
ly020044
2021-03-24 08:41:12 +08:00
哎呀我的大宝贝,为啥不先看一下教程?好好看一下指针吧
dong568789
2021-03-24 10:04:26 +08:00
6 楼在说啥?
zjj19950716
2021-03-24 20:09:14 +08:00
george404
2021-03-25 06:54:35 +08:00
@dong568789 擦,忘了吧第二个的*A 的指针去掉。。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/764415

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX