嵌套结构 - 获取“基础”结构

时间:2013-10-11 20:21:32

标签: inheritance struct go nested

(作为后续问题:nested struct initialization literals)。

现在我可以使用易于编写的文字初始化结构,稍后在我的代码中需要访问父结构的成员,但不知道具体的派生类型。就像这样:

type A struct {
    MemberA string
}

type B struct {
    A
    MemberB string
}

然后我就这样使用它:

b := B {
    A: A { MemberA: "test1" },
    MemberB: "test2",
}
fmt.Printf("%+v\n", b)

var i interface{} = b

// later in the code, I only know that I have something that has a nested A,
// I don't know about B (because A is in a library and B is in the 
// calling code that uses the library).

// so I want to say "give me the A out of i", so I try a type assertion

if a, ok := i.(A); ok {
    fmt.Printf("Yup, A is A: %+v\n", a)
} else {
    fmt.Printf("Aristotle (and John Galt) be damned! A is NOT A\n")
}

// no go

我看到的选项是:

  • 我可以使用反射来查找名为“A”的成员,并假设它是正确的类型,请使用它。这将是可行的,但效率较低,当然更“笨重”。

  • 我可以要求调用者实现一个接口(如HasA { Aval() A }或类似的接口,返回A的实例。到目前为止,这是我能想到的最好的主意。

  • 另一点是我可以让调用者传递A值(即在上面的示例中,var i interface{} = b变为var i A = b.A)。但是发生的事情是我实际上动态地迭代B的成员并用它们做事,所以我需要更多的“派生”类型。 (我从这个问题中省略了这一点,因为它更像是为什么我遇到这个问题的背景,而且与问题的技术答案无关。)

如果我能像在Java中那样将其“转换为A”,那就太棒了。是否有更优雅的方式来做到这一点。

4 个答案:

答案 0 :(得分:2)

如果你有一个未知类型b,挖掘嵌入字段的唯一方法是通过反射。

clunky:

// obviously missing various error checks
t := reflect.ValueOf(i)
fmt.Printf("%+v\n", t.FieldByName("A").Interface().(A))

struct embedding是继承,并且尝试使用它本身将继续提出这样的问题。在go中实现一般多态的方法是使用接口。

我认为处理这种情况最干净的方法是使用通用接口,并为要处理的字段使用适当的访问器方法。你会看到stdlib的例子,例如: http.ResponseWriter,其Header()方法用于访问实际的响应标头。

答案 1 :(得分:2)

  

如果我能像在Java中那样将它投射到A"那将是很棒的。是否有更优雅的方式来做到这一点。

盲目投射几乎总是对你的代码质量来说是坏消息所以它实际上非常好 这样做很难。

我会去接口路由,因为它也会消除用于存储interface{}的{​​{1}}。 如果你确实有各种各样的类型,他们只分享它们嵌入b接口 提供A对我来说似乎很好。

作为奖励,您可以直接在AVal() A上定义AVal() A,这样您就不需要为嵌入A的每种类型实施它。

示例(on play):

A

请注意,我现在使用指针值,以便type A struct { MemberA string } func (a *A) AVal() *A { return a } type B struct { *A MemberB string } type AEmbedder interface { AVal() *A } func main() { b := B { A: &A { MemberA: "test1" }, MemberB: "test2", } var i AEmbedder = b a := i.AVal() fmt.Printf("Yup, A is A: %+v\n", a) } 不返回副本 AVal() *A

的相应实例

答案 2 :(得分:0)

这对我有用。虽然它不是像你想要的那样直接转换,但它确实提供了正确的对象实例

fmt.Printf("It's", i.(B).A)

我希望它有所帮助!

答案 3 :(得分:0)

稍微使用它,我得到了它的工作:http://play.golang.org/p/-bbHZr-0xx

我不能100%确定为什么会这样,但我最好的理论是当你打电话时

a := i.(A)

您正在尝试对iA中存储的内容进行类型转换的接口版本。所以你首先需要告诉它它实际上是B,然后你可以访问嵌套在它里面的A

a := i.(B).A