douyan4900 2013-10-11 20:21
浏览 65
已采纳

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

(As a followup this question: nested struct initialization literals).

Now that I can initialize a struct with literals that are easy to write, I later in my code need access members of the parent struct, but without knowing the concrete derived type. It's like this:

type A struct {
    MemberA string
}

type B struct {
    A
    MemberB string
}

And then I use it like this:

b := B {
    A: A { MemberA: "test1" },
    MemberB: "test2",
}
fmt.Printf("%+v
", 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
", a)
} else {
    fmt.Printf("Aristotle (and John Galt) be damned! A is NOT A
")
}

// no go

The options I see are:

  • I could use reflection to look for a member called "A" and, assuming it's the right type, use it. This would be workable but less efficient and certainly more "clunky".

  • I could require the caller to implement an interface (like HasA { Aval() A } or similar which returns an instance of A. So far this is the best idea I could think of.

  • The other point is that I could just have the caller pass a A value (i.e. in the example above, var i interface{} = b becomes var i A = b.A). But what's happening is I actually dynamically iterate over the members of B and do stuff with them, so I need that more "derived" type in order to that. (I've omitted that from the question because it's more just background as to why I'm running into this and is not pertinent to the technical answer of the question.)

It would be great if I could just "cast it to A", as you would in Java. Is there a more elegant way to do that.

  • 写回答

4条回答 默认 最新

  • dongpengyu1363 2013-10-11 21:27
    关注

    It would be great if I could just "cast it to A", as you would in Java. Is there a more elegant way to do that.

    Blind casting is almost always bad news for your code quality so it is actually quite good to make it difficult to do so.

    I would go the interface route as it would also eliminate the interface{} you use to store b. If you indeed have a high variety of types and they only share that they embed A an interface which offers AVal() A seems good to me.

    As a bonus, you could define AVal() A on A directly so you don't need to implement it for every type that embeds A.

    Example (on play):

    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
    ", a)
    }
    

    Note that I'm now using a pointer value so that AVal() *A does not return a copy but the respective instance of A.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 java报错:使用mybatis plus查询一个只返回一条数据的sql,却报错返回了1000多条
  • ¥15 Python报错怎么解决
  • ¥15 simulink如何调用DLL文件
  • ¥15 关于用pyqt6的项目开发该怎么把前段后端和业务层分离
  • ¥30 线性代数的问题,我真的忘了线代的知识了
  • ¥15 有谁能够把华为matebook e 高通骁龙850刷成安卓系统,或者安装安卓系统
  • ¥188 需要修改一个工具,懂得汇编的人来。
  • ¥15 livecharts wpf piechart 属性
  • ¥20 数学建模,尽量用matlab回答,论文格式
  • ¥15 昨天挂载了一下u盘,然后拔了