V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
qq316107934
V2EX  ›  Go 编程语言

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

  •  
  •   qq316107934 · 2019-10-10 22:19:12 +08:00 · 3156 次点击
    这是一个创建于 1900 天前的主题,其中的信息可能已经有所发展或是发生改变。

    猜猜会输出什么?

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

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

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

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

    简单说来,在一个函数内部对一个形参本身进行的任何修改都不会体现到相应传递的实参上。
    因为此形参只不过是相应实参的一个副本。
    Leigg
        9
    Leigg  
       2019-10-11 09:03:02 +08:00 via Android
    一楼没说到点子上,二楼讲对了
    f4nyc
        10
    f4nyc  
       2019-10-11 19:23:24 +08:00 via iPhone
    对不起,我愚蠢了,完全是半桶水瞎晃悠,慎之戒之。
    @heimeil
    @lance6716
    @mornlight
    @reus
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5807 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 06:25 · PVG 14:25 · LAX 22:25 · JFK 01:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.