我今天遇到了一个问题,能够找到它并快速修复它,但不完全理解为什么 golang 语义是这样的。
我正在使用 Go 1.10。
package main
import "fmt"
type T struct {
V int
}
var testT = T{}
func main() {
t := &(*(&testT))
t.V = 4
fmt.Println(t, testT) // test.V == t.V -> t == &testT
t1 := &testT
t2 := *t1
t3 := &t2
t3.V = 5
fmt.Println(t3, testT) // t3.V == 4 and test.T == 4 -> t3 != &testT
}
输出
&{4} {4}
&{5} {4}
我期望不等于 &testT,因此具有与 t3 相同的语义,但相反,如果我将中间结果存储在变量中,我看到 &(*(&)) 序列没有相同的语义
我的问题
这种行为的原因是什么?
当你这样做时:
t1 := &testT
t2 := *t1
t3 := &t2
t3.V = 5
你取testT
的地址,存储在t1
。然后在下一行中创建一个新的、不同的变量t2
,它将具有与t1
或testT
不同的内存空间和地址。然后t3
将存储这个新的、不同的变量的地址,它与t1
或testT
无关。
执行此操作时:
t := &(*(&testT))
你取testT
的地址,然后取消引用指针(你得到testT
"back"),然后你再次取这个值的地址,这将是testT
的地址,没有创建新的变量。所以t
会指向testT
.
这是正常和合乎逻辑的,没有什么令人惊讶的。规范中的相关部分:地址运算符:
对于指针类型为
*T
的操作数x
,指针间接寻址*x
表示x
指向的类型为T
的变量。
所以变量testT
的地址&testT
,*(&testT)
会把testT
变量还给你。再次获取其地址将与&testT
相同。
可能暗示这一点的是获取复合文字的地址。规格: 复合文字:
获取复合文本的地址会生成一个指向使用文本值初始化的唯一变量的指针。
当您获取复合文字的地址时(例如&image.Point{}
),这确实会在后台创建一个新的匿名变量,并且该匿名变量的地址将是表达式的结果。但是获取变量的地址不会创建新变量。