Golang结构初始化

Golang结构初始化,go,Go,有这样一个简单的结构: type Event struct { Id int Name string } 这两种初始化方法的区别是什么 e1 := Event{Id: 1, Name: "event 1"} e2 := &Event{Id: 2, Name: "event 2"} 我为什么要使用这两种初始化方法?e1的类型是事件e2的类型是*事件。初始化实际上是相同的(使用复合文字语法,也不确定该术语是Go还是C#或两者都是?),但对于e2

有这样一个简单的结构:

type Event struct {
    Id         int
    Name       string
}
这两种初始化方法的区别是什么

e1 := Event{Id: 1, Name: "event 1"}
e2 := &Event{Id: 2, Name: "event 2"}

我为什么要使用这两种初始化方法?

e1的类型是
事件
e2的类型是
*事件
。初始化实际上是相同的(使用复合文字语法,也不确定该术语是Go还是C#或两者都是?),但对于
e2
您使用“操作符地址”
&
,因此它返回指向该对象的指针,而不是实例本身。

第一种方法

e1 := Event{Id: 1, Name: "event 1"}
e2 := &Event{Id: 2, Name: "event 2"}
e1 := Event{Id: 1, Name: "event 1"}
正在将变量
e1
初始化为类型为
Event
的值

第二

e2 := &Event{Id: 1, Name: "event1"}
正在将
e2
初始化为指向类型
Event
的值的指针正如您在注释中所述,在给定类型的值上定义的方法集是在指向该类型值的指针上定义的方法集的子集。这意味着如果你有一个方法

func (e Event) GetName() string {
    return e.Name
}
然后
e1
e2
都可以调用此方法,但如果您有其他方法,请说:

func (e *Event) ChangeName(s string) {
    e.Name = s
}
然后,
e1
无法使用
ChangeName
方法,而
e2
无法使用

这(
e1
无法使用
ChangeName
方法,而
e2
是)并非如此(尽管在撰写此帮助时可能已经如此),这要感谢@DannyChen提出此问题,以及@GilbertNwaiwu测试并在下面的评论中发布。

(为了解决上面删除的部分:在结构类型上定义的方法集包括为该类型定义的方法和指向该类型的指针

相反,Go now会自动取消对方法的参数引用,这样,如果一个方法接收到指针,Go就会对指向该结构的指针调用该方法,如果该方法接收到值,Go就会对该结构指向的值调用该方法。此时,我更新此答案的尝试可能缺少语义中的一些重要内容cs所以如果有人想纠正或澄清这个问题,请随意添加一条评论,指向一个更全面的答案。下面是一个演示这个问题的示例:

在某种程度上,指针和值作为函数上定义的方法的参数的工作方式的这种变化会影响下面讨论的某些方面,但我将不编辑其余部分,除非有人鼓励我更新它,因为在通过值传递的语言与指针传递的语言的一般语义的上下文中,它似乎或多或少是正确的。)

至于指针和值之间的区别,这个例子是说明性的,因为指针通常在Go中使用,以允许您改变变量所指向的值(但也有很多原因可以使用指针!尽管对于典型的使用,这通常是一个可靠的假设)。因此,如果您将
ChangeName
定义为:

func (e Event) ChangeName(s string) {
    e.Name = s
}
如果在值接收器上调用此函数,则该函数将不会非常有用,因为值(不是指针)不会保留传递到函数中时对其所做的更改。这与语言设计中如何分配和传递变量有关:


你可以在围棋场的这个例子中看到这一点:

e1.SomeMethod()与*e2.SomeMethod本质上是一样的,对吗?Go将执行(*e1).SomeMethod(),如果我没有弄错的话。@sheldon_cooper不完全正确,它们是不同类型的。如果我有一个像
func(e*Event)Test()
这样的方法,并尝试执行
e1.Test()
,我将得到一个编译器错误。我可以做
ep:=&e1
,然后做
ep.Test()
,或者你也可以做内联的或者其他任何事情,但是你必须得到指针才能调用用指针作为接收器定义的方法。基本上,在调用方法时,go不会为您按摩或强制类型。它必须与方法定义中的内容匹配。不过,您可以很容易地将值转换为指针或值指针。是的,我理解引用和值接收器类型之间的区别。我在规范中提到了这一点:“如果(类型)x的方法集包含m,并且参数列表可以分配给m的参数列表,那么方法调用x.m()是有效的。如果x是可寻址的,并且&x的方法集包含m,那么x.m()是(&x)的缩写。m():”规范的URL是:。谢谢你的解释。我将对此进行实验。这些类型的构造对于Go来说是非常基本的东西,在Go()的教程中有很好的解释。再来一次你的旅行怎么样?旅行中有一些微妙的不清楚的地方。初始化结构时,获取指针与实例本身是有区别的。那么e1不能使用ChangeName方法,而e2是。”这个结论仍然正确吗?@DannyChen:刚刚测试过。不对。两者都可以使用method@GilbertNwaiwu似乎情况并非如此,与你描述的一致,我将编辑原始帖子,感谢你发现这种不一致。我有点感兴趣的是,在指向某个类型的指针上定义的方法是否总是无法被该类型的值调用,或者这是否是一个较新的发展。粗略搜索显示如下帖子:链接到此线程:因此,这可能是在最近的更新中更改的,但谷歌搜索指针方法接收器并没有从Go发布历史中返回任何信息。我已经有一段时间没有写任何围棋了,所以我与语言最近的变化失去了联系,我也不打算查看这个版本的发布历史。也许有人可以插话。