英文:
Directly vs indirectly nested structs
问题
在Go的xml:Unmarshal文档中有一个示例,用于解析以下XML:
<Person>
<FullName>Grace R. Emlin</FullName>
<Company>Example Inc.</Company>
<Email where="home">
<Addr>gre@example.com</Addr>
</Email>
<Email where='work'>
<Addr>gre@work.com</Addr>
</Email>
<Group>
<Value>Friends</Value>
<Value>Squash</Value>
</Group>
<City>Hanga Roa</City>
<State>Easter Island</State>
</Person>
使用以下结构体:
type Address struct {
City, State string
}
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
请注意,Result
包含对单独定义的 Address
的引用。显然,这段代码是有效的。
当我尝试解析以下XML时:
<C>
<D>
<E>Fred</E>
<F>42</F>
</D>
</C>
使用以下结构体:
type D struct {
E string
F int
}
type C struct { // 编译通过,但结果为空。
D
}
我得到了空的结果 {{ 0}}
。然而,下面的结构体可以正常工作,产生结果 {{Fred 42}}
:
type C struct { // 这个可以正常工作。
D struct {
E string
F int
}
}
请参考Playground示例。
我是否忽略了关于结构体的一些微妙的点?
英文:
In the Go documentation for xml:Unmarshal there is an example that unmarshals this xml
<Person>
<FullName>Grace R. Emlin</FullName>
<Company>Example Inc.</Company>
<Email where="home">
<Addr>gre@example.com</Addr>
</Email>
<Email where='work'>
<Addr>gre@work.com</Addr>
</Email>
<Group>
<Value>Friends</Value>
<Value>Squash</Value>
</Group>
<City>Hanga Roa</City>
<State>Easter Island</State>
</Person>
using these structs
type Address struct {
City, State string
}
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
Note that Result
contains a reference to the separately defined Address
. Obviously, this code works.
When I try to unmarshal this xml
<C>
<D>
<E>Fred</E>
<F>42</F>
</D>
</C>
using these structs
type D struct {
E string
F int
}
type C struct { // Compiles OK but result empty.
D
}
I get empty results {{ 0}}
. However the struct below works OK producing {{Fred 42}}
type C struct { // This works.
D struct {
E string
F int
}
}
See Playground example.
Am I missing some subtle point about structs?
答案1
得分: 6
当你这样做时:
type C struct {
D
}
这被称为嵌入(D
是一个匿名字段或嵌入字段)。你可以将其视为嵌入类型的字段(和方法)成为嵌入者类型的一部分(它们被"提升")。所以在这种情况下,写C.E
和C.F
是"合法"的。
当你这样做时:
type C struct {
D struct {
E string
F int
}
}
这不是嵌入(或"嵌套")。这里的D
是C
类型的一个"常规"、命名字段。D
是字段的名称,后面跟着一个匿名的type literal,表示字段的类型。在这种情况下,写C.E
和C.F
是不合法的,只能写C.D.E
和C.D.F
。这是你尝试解组的XML结构的正确映射,因此这样可以工作(在Go Playground上试一试)。
请注意,如果你将嵌入改为常规字段,它也会工作(在Go Playground上试一试):
type C struct {
D D
}
还要注意,如果你在字段标签中指定XML元素路径,可以跳过整个D
包装结构:
type C struct {
E string `xml:"D>E"`
F int `xml:"D>F"`
}
在Go Playground上试一试。
英文:
When you do this:
type C struct {
D
}
This is called embedding (D
is an anonymous field or embedded field). You may think of this as if the fields (and methods) of the embedded type become part of the embedder type (they get promoted). So in this case it's "legal" to write C.E
and C.F
.
When you do:
type C struct {
D struct {
E string
F int
}
}
This is not embedding (or "nesting"). Here D
is a "regular", named field of the C
type. D
is the name of the field, which is followed by an anonymous type literal, the type of the field. Here it is not legal to write C.E
nor C.F
, only C.D.E
and C.D.F
. And this is the proper mapping of the XML structure you try to unmarshal, hence this works (try it on the Go Playground).
Note that if you change the embedding to a regular field, it will also work (try it on the Go Playground):
type C struct {
D D
}
Also note that you can skip the whole D
wrapper struct if you specify the XML element paths in the field tags:
type C struct {
E string `xml:"D>E"`
F int `xml:"D>F"`
}
Try it on the Go Playground.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论