一个容易让 gopher 理解不当的小细节

共 1465字,需浏览 3分钟

 ·

2021-02-05 09:32

周末,一位热情好学的读者给我发了条私信,聊天内容如下图所示。小菜刀猜测可能会有一部分读者也存在跟他一样的疑惑,所以特此简单地探讨一下该问题。

首先需要纠正一点的是,他给出的代码是不能通过编译的。
1type S string   
2p := &S{"test"}
由于 S 对象是 string 的别名,它是不可寻址的,编译器会返回 cannot take the address of S("test") 的错误。因此,将例子改为如下所示。
1    type S struct {
2        s string
3    }
4    p := &S{"test"}
5    c := p
6    p = nil
7    fmt.Println(p, c)
输出结果
1<nil> &{test}
其实,读者的疑问就在于:为什么修改 pc 却没有变化?

问题讨论

为了回答这个疑问,我们在代码中增加了几处详细打印如下
1    type S struct {
2        s string
3    }
4    p := &S{"test"}
5    c := p
6    fmt.Printf("p指向的地址:%p c指向的地址:%p\n", p, c)
7    fmt.Printf("p本身的地址:%p c本身的地址:%p\n", &p, &c)
8    p = nil
9    fmt.Println(p, c)
输出结果
1p指向的地址:0xc00008e1e0 c指向的地址:0xc00008e1e0
2p本身的地址:0xc0000ae018 c本身的地址:0xc0000ae020
3<nil> &{test}
该过程图解如下

pc 都是指向同一块内存的 S 类型指针对象,p = nil 的操作,不是修改它指向地址中的内容,而是修改它的指向,因此 p 的指向变化,不会对 c 造成任何影响。
将上述代码中 p = nil 修改为 p.s = "sss" ,即代码如下
1    type S struct {
2        s string
3    }
4    p := &S{"test"}
5    c := p
6    p.s = "sss"
7    fmt.Println(p, c)
此时的结果
1&{sss} &{sss}
该过程图解如下

此时,p 对指向地址的内容做了修改,此修改同时影响到了 c

总结

以本文中的例子简单总结一下:pc 都是 S 类型的指针对象,它们对同一个指向内容的修改会相互影响。但是,如果是它们的指向发生变化,那么 pc 将不再存在任何关系,它们的内容修改将不再相互影响。所以,如果将上文中  p = nil 修改为 p = &S{"sss"},它同样不会对 c 造成任何影响。
因此,对于指针类型对象,我们要注意区分的就是修改操作到底是修改指向地址的内容还是修改指针的指向。能够分清这个,那么本文的问题也就不再对你造成威胁了。

推荐阅读


福利

我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。

浏览 9
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报