一个意外的 Golang 接口方法的非预期输出,你们能答对吗?

2019-10-10 22:19:12 +08:00
 qq316107934

猜猜会输出什么?

如果有大佬答对了求解释,非常感谢!

package main

import(
	"fmt"
	"encoding/json"
)

type a []int


func main(){
	b := &a{0}
	fmt.Printf("%v\n",*b)
	b.Scan()
	fmt.Printf("%v\n",*b)
	b.Scan2()
	fmt.Printf("%v\n",*b)

}

func (i *a) Scan(){
	i = &a{1}
}

func (i *a) Scan2(){
	json.Unmarshal([]byte{'[','2',']'},i)
}
3131 次点击
所在节点    Go 编程语言
10 条回复
f4nyc
2019-10-10 22:39:45 +08:00
golang 只有值传递,指针在这里也无关紧要。
重点是你要搞清楚 map slice chan 在内存中存储的方式。
你用 gdb 单步看看 b 的地址就明白了。
heimeil
2019-10-10 22:40:07 +08:00
Scan: 指针也是值类型,改变的只是当前作用域`i`的存的指针值,不是改的`i`指针指向的内存
Scan2: `json.Unmarshal`里面实际是解引用改变原地址的值,等同于`*i = a{2}`
qq316107934
2019-10-10 22:50:13 +08:00
@f4nyc @heimeil 感谢两位大佬的点拨,一针见血啊!在内存中指针被复制了一份修改并未反应回原指针,导致值未改变。再次感谢大佬!!困扰了我一晚上的问题,我果然还是太弱鸡了😭
f4nyc
2019-10-10 22:53:08 +08:00
@heimeil 我认为你这是误导。和指针没有关系,是 slice 在内存中的存储方式导致的。去掉所有的&和*这段代码还是一样的结果。但把[]int 换成 struct 马上就能得到所谓的预期输出。
lance6716
2019-10-10 23:26:02 +08:00
@f4nyc 啥意思,去掉&和*当然一样了,除非手动解引用。
struct 的.就是解引用
mornlight
2019-10-11 00:08:13 +08:00
@f4nyc 其实楼主没讲清楚他的问题,我估计是说为啥两个 Scan 一个不能改变入参另一个不能改变,2 楼讲的内容应该更能回应楼主的疑惑。核心就在于 i = &a{1} 这个地方 i 本身被重新赋值,这个赋值不影响它指向的那块内存内容。

slice 是一种特殊的 struct,传参的场景可以当 struct 一样理解。
reus
2019-10-11 00:26:13 +08:00
@f4nyc 请问你知道 *i = a{2} 和 i = &a{2} 的区别吗?
liulaomo
2019-10-11 06:06:27 +08:00
虽然我非常抵触使用引用来描述一个值这种说法(因为常常引起误解),
这里为了和大家保持一致,暂时还是使用此说法。

当修改一个指针参数所指的值的时候,此指针可以被看做是一个引用值。
但是当此指针参数本身被修改的时候,此此指针应该被看做是一个非引用值。

简单说来,在一个函数内部对一个形参本身进行的任何修改都不会体现到相应传递的实参上。
因为此形参只不过是相应实参的一个副本。
Leigg
2019-10-11 09:03:02 +08:00
一楼没说到点子上,二楼讲对了
f4nyc
2019-10-11 19:23:24 +08:00
对不起,我愚蠢了,完全是半桶水瞎晃悠,慎之戒之。
@heimeil
@lance6716
@mornlight
@reus

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

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

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

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

© 2021 V2EX