直接嵌套结构体 vs 间接嵌套结构体

huangapple go评论93阅读模式
英文:

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

    &lt;Person&gt;
		&lt;FullName&gt;Grace R. Emlin&lt;/FullName&gt;
		&lt;Company&gt;Example Inc.&lt;/Company&gt;
		&lt;Email where=&quot;home&quot;&gt;
			&lt;Addr&gt;gre@example.com&lt;/Addr&gt;
		&lt;/Email&gt;
		&lt;Email where=&#39;work&#39;&gt;
			&lt;Addr&gt;gre@work.com&lt;/Addr&gt;
		&lt;/Email&gt;
		&lt;Group&gt;
			&lt;Value&gt;Friends&lt;/Value&gt;
			&lt;Value&gt;Squash&lt;/Value&gt;
		&lt;/Group&gt;
		&lt;City&gt;Hanga Roa&lt;/City&gt;
		&lt;State&gt;Easter Island&lt;/State&gt;
	&lt;/Person&gt;

using these structs

    type Address struct {
		City, State string
	}
	type Result struct {
		XMLName xml.Name `xml:&quot;Person&quot;`
		Name    string   `xml:&quot;FullName&quot;`
		Phone   string
		Email   []Email
		Groups  []string `xml:&quot;Group&gt;Value&quot;`
		Address
	}

Note that Result contains a reference to the separately defined Address. Obviously, this code works.


When I try to unmarshal this xml

&lt;C&gt;
  &lt;D&gt;
    &lt;E&gt;Fred&lt;/E&gt;
    &lt;F&gt;42&lt;/F&gt;
  &lt;/D&gt;
&lt;/C&gt;

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.EC.F是"合法"的。

当你这样做时:

type C struct {
    D struct {
      E string
      F int
    }
}

这不是嵌入(或"嵌套")。这里的DC类型的一个"常规"、命名字段。D是字段的名称,后面跟着一个匿名的type literal,表示字段的类型。在这种情况下,写C.EC.F是不合法的,只能写C.D.EC.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:&quot;D&gt;E&quot;`
	F int    `xml:&quot;D&gt;F&quot;`
}

Try it on the Go Playground.

huangapple
  • 本文由 发表于 2017年2月27日 23:30:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/42489564.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定