在Go语言中使用DRY结构标签

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

DRY struct tags in Go

问题

我正在解析XML,而在文档的每个级别上,都有一个description

这是一个玩具示例:

<obj>
	<description>外部对象</description>
	<subobjA>
		<description>第一种子对象</description>
		<foo>一些内容</foo>
	</subobjA>
	<subobjB>
		<description>第二种子对象</description>
		<bar>一些其他内容</bar>
	</subobjB>
</obj>

这意味着每个涉及的结构体都有一个相同的Description成员,带有相同的标签`xml:"description,omitempty"`

这是一个可运行的代码:http://play.golang.org/p/1-co6Qcm8d

我希望Description标签是DRY的。显而易见的想法是像这样做:

type Description string `xml:"description,omitempty"`

然后在整个代码中使用Description类型。然而,只有结构体成员可以有标签。请参阅我想要编写的内容:http://play.golang.org/p/p83UrhrN4u,它无法编译。

可以创建一个Description结构体并重复嵌入它,但这会在访问时增加一层间接性。

有其他方法可以解决这个问题吗?

英文:

I'm parsing XML, and at most every level of the document, there's a description.

Here's an toy example:

<obj>
	<description>outer object</description>
	<subobjA>
		<description>first kind of subobject</description>
		<foo>some goop</foo>
	</subobjA>
	<subobjB>
		<description>second kind of subobject</description>
		<bar>some other goop</bar>
	</subobjB>
</obj>

This means that every struct involved has an identical Description member, with an identical tag `xml:"description,omitempty"`.

Here's functioning code: http://play.golang.org/p/1-co6Qcm8d

I'd rather the Description tags be DRY. The obvious thing to want to do is something like:

type Description string `xml:"description,omitempty"`

and then use the type Description throughout. However, only struct members can have tags. See http://play.golang.org/p/p83UrhrN4u for what I want to write; it doesn't compile.

One could create a Description struct and embed it repeatedly, but that adds a layer of indirection when accessing.

Is there another way to go about this?

答案1

得分: 4

嵌入重构的Description结构体(正如你已经建议的那样)是正确的方法:

(Playground)

type describable struct{
    Description string `xml:"description"`
}

type subobjA struct {
    describable
    XMLName     xml.Name `xml:"subobjA"`
}

type subobjB struct {
    describable
    XMLName     xml.Name `xml:"subobjB"`
}

type obj struct {
    XMLName     xml.Name `xml:"obj"`
    A           subobjA
    B           subobjB
}

所提到的间接层不存在。引用规范中的内容:

> 结构体x中的匿名字段f的字段或方法f被称为被提升,如果x.f是一个合法的选择器,表示该字段或方法f。
>
> 被提升的字段的行为就像结构体的普通字段一样,除了它们不能在结构体的复合字面量中用作字段名。

所以你可以这样做:

err := xml.Unmarshal([]byte(sampleXml), &sampleObj)
fmt.Println(sampleObj.Description)
fmt.Println(sampleObj.A.Description)

sampleObj.describable.Description被提升为sampleObj.Description,所以这里没有进一步的间接层。

英文:

Embedding a re-factored Description struct (as you already suggested) is the way to go:

(Playground)

type describable struct{
    Description string `xml:"description"`
}

type subobjA struct {
    describable
    XMLName     xml.Name `xml:"subobjA"`
}

type subobjB struct {
    describable
    XMLName     xml.Name `xml:"subobjB"`
}

type obj struct {
    XMLName     xml.Name `xml:"obj"`
    A           subobjA
    B           subobjB
}

The mentioned layer of indirection does not exist. To cite the spec on that topic:

> A field or method f of an anonymous field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.
>
> Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.

So you can do this:

err := xml.Unmarshal([]byte(sampleXml), &sampleObj)
fmt.Println(sampleObj.Description)
fmt.Println(sampleObj.A.Description)

sampleObj.describable.Description is promoted to be sampleObj.Description, so no further layer of indirection here.

huangapple
  • 本文由 发表于 2013年5月7日 04:11:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/16406459.html
匿名

发表评论

匿名网友

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

确定