【问题标题】:How to create a slice of structs that embeds another?如何创建一个嵌入另一个结构的切片?
【发布时间】:2017-12-18 23:58:38
【问题描述】:

我有以下:

https://play.golang.org/p/q2NUMzbw6-

package main

import "fmt"

type A struct {
    Name string
    Address string
}

type B struct {
    A
}

type C struct {
    A
}

type D struct {
    A
}

//....more structs that embed A

type myinterface interface {
    SetName(string)
    SetAddress(string)
}

func run() *A {
    // iterate over a slice of structs that embed A.... how????
    for _, s := range []*A{
        &B{}, &C{}, &D{},
    } {
        s.SetName("Bob")
        s.SetAddress("Maine")
        // do some other stuff that gets very verbose w/out a slice...
        return s.A
    }
}

func main() {
    a := run()
    fmt.Println(a)
}

我需要遍历所有嵌入 A 的结构,但我很难这样做。以上不起作用“不能将 B 文字(类型 *B)用作数组或切片文字中的 *A 类型”。最好的方法是什么?

【问题讨论】:

    标签: go


    【解决方案1】:

    在A上声明满足接口的方法:

    func (a *A) SetName(s string) {
        a.Name = s
    }
    
    func (a *A) SetAddress(s string) {
        a.Address = s
    }
    

    在范围内使用该接口的一部分:

    for _, s := range []myinterface{&B{}, &C{}, &D{}} {
       ...
    }
    

    playground example

    【讨论】:

      【解决方案2】:

      认为 Go 中的类型嵌入类似于其他语言中的继承是一种常见的误解。

      实际上,类型嵌入类似于其他语言中的组合。

      在您的示例中,类型BA 没有任何关系,除了通过在B 中嵌入A 您可以直接在@ 上调用A 的方法987654327@.

      您可以在此处阅读更多信息:

      https://golang.org/doc/effective_go.html#embedding

      为了模仿“继承”,您需要使用接口。

      您应该使用myinterface 作为数组类型,以便以通用方式处理所有这些结构。

      【讨论】:

        【解决方案3】:

        编译器告诉你问题:你不能使用类型B作为类型A(你也不能使用类型A作为类型B);类型根本不一样。您应该在myinterface 的一部分范围内。

        但是,这不是完整的解决方案,因为 s.A 将无法工作,因为 s 现在具有 myinterface 类型(具有基础类型 *B*C*D),并且没有方法命名为A 属于myinterface

        您可以通过将另一个方法aSelf() *A 添加到myinterface 并使用接收器类型*A 实现aSelf 来解决此问题,该接收器仅返回接收器。这样BC等都可以使用这个方法。请注意,在这种情况下,您不能简单地将方法命名为 A,因为 B.A(和 C.A 等)将是模棱两可的:.A 是指嵌入的 A 字段本身还是 @嵌入A字段的987654346@方法?如果方法不会被导出,您可以将其命名为a,否则您需要使用其他名称,例如前面提到的aSelf

        以下是要更改/添加的相关位:

        func (a *A) aSelf() *A {
            return a
        }
        
        type myinterface interface {
            SetName(string)
            SetAddress(string)
            aSelf() *A
        }
        
        func run() *A {
            // iterate over a slice of myinterface
            for _, s := range []myinterface{
                &B{}, &C{}, &D{},
            } {
                s.SetName("Bob")
                s.SetAddress("Maine")
                // do some other stuff that gets very verbose w/out a slice...
                return s.aSelf()
            }
            return nil
        }
        

        Playground link

        【讨论】:

          猜你喜欢
          • 2023-03-18
          • 2019-04-12
          • 2013-10-17
          • 2020-04-01
          • 2014-09-12
          • 1970-01-01
          • 2014-04-16
          • 1970-01-01
          相关资源
          最近更新 更多