我有这段Go代码片段,其中我试图分别使用两个函数f
和f2
来更改常规int和结构中int的值。我不明白为什么我需要做*i
来更改int的值,但是当我在结构中更改X的值时我不需要这样做。
type Point struct {
X int
}
func t(i *int) {
*i = 20
}
func t2(p *Point) {
p.X = 200
}
func main() {
g := 30
t(&g)
fmt.Println(g)
p := Point{3}
t2(&p)
fmt.Println(p)
}
答案 0 :(得分:3)
考虑这两个函数的最简单方法是在t2
函数中,使用指向基础结构的指针来更改结构的字段。在t
函数中,您正在更改整个基础对象(整数)。
实际上,您可以写p.X
的事实实际上只是一件好事。在C之类的语言中,如果要对非指针变量进行操作,则只能使用p.X
。对于指针,您必须使用p->X
来表示您正在使用间接访问字段,或者实际上是取消引用指针((*p).X
)。
在内部,go仍然做同样的事情,它只允许您省略显式的取消引用,并且不需要间接运算符。
但是,两个函数都是不等效的。 Point
是一个结构,具有一个或多个字段。另一种类型是*int
,一个int是单个标量值。要使t2
等价(并重新分配整个基础对象),您必须将代码更改为与在*int
情况下必须执行的代码相同:
func t2(p *Point) {
*p = Point{
X: 200,
Y: p.Y,
}
}
根据以下注释:TL; DR版本是,如果您访问结构类型的字段之一,则不必显式取消对结构类型的指针的引用。您必须在C / C ++中做到这一点,但是go编译器会为您解决这一问题。可以看出,您使用的是指针类型的变量,并且以与C编译器编译p.X
相同的方式编译p->X
。因此,您无需显式取消引用p
。
如果将*p.X
声明为:
Point
。
type Point struct {
X *int
}
因为表达式p.X
的计算结果为类型*int
的操作数,因此需要对其进行相应的处理。
答案 1 :(得分:2)
由于i
是类型*int
的指针,并且您要修改指向的对象,因此必须编写*i
。
相同的语法也适用于结构,例如您可以编写(*p).X
,但这是一项经常性的操作,因此该规范允许使用p.X
,这意味着(*p).X
,没有歧义,并且是方便的快捷方式。
作为例外,如果
x
的类型是defined指针类型,并且(*x).f
是表示字段(但不是方法)的有效选择器表达式,则{{1} }是x.f
的简写。