英文:
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
结构体(正如你已经建议的那样)是正确的方法:
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:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论