【问题标题】:Embedded types and polymorphism with structs嵌入类型和结构的多态性
【发布时间】:2015-10-07 09:06:57
【问题描述】:

我正在创建一个 API,我有两个不同的 JSON 响应结构;一个用于单个记录,一个用于记录集合:

type Model struct {
  Id uint
}

type Collection struct {
  Records []Model
}

Model 只是数据库数据的结构表示(例如,用户),Collection 是模型的集合。

问题是会有单独的结构嵌入Model 类型,如下所示:

type User struct {
    *Model
    Name string
}

由于 User 不满足 Model 类型,我不能像这样将它附加到 Collection 结构中:

user := User{&Model{1}, "Jon"}
uc := &Collection{[]User{user}}

如何使 Records 结构接受实现 Model 的结构类型?

【问题讨论】:

    标签: struct go polymorphism


    【解决方案1】:

    你有两个选择:

    • 创建另一个集合类型
    • 改用接口

    如果您没有太多的 foo 和 bar,则可以选择实现单独的集合,例如 UserCollectionBarCollectionFooCollection

    另一种方法是使用通用空接口类型interface{},它将保存任何类型的值(因为每种类型的每个实例都满足空接口):

    type Collection struct {
        Records []interface{}
    }
    

    这有许多缺点,例如每次访问Records 字段时都必须进行类型断言,可能会错误地将所有内容放入其中,并且必须使用反射来进行大多数操作。

    使用接口的更好方法是实现一个模型接口,并让作为模型的每个类型都实现该接口:

    type Model interface {
        ImplementsModel()
    }
    
    type BaseModel struct {
        Id uint
    }
    
    func (b *BaseModel) ImplementsModel() {}
    
    type User struct {
        *BaseModel
        Name string
    }
    
    type Collection struct {
        Records []Model
    }
    

    当然,一旦你有了有意义的方法,你就可以删除ImplementsModel 虚拟方法。这个虚拟方法只是用来区分接口和空接口,因此您不能将整数值或字符串代替实际模型放入集合中。

    【讨论】:

    • 但在您的示例中,虽然我可以将 BaseModel 存储到 Records 中,但如何才能再次取回这些 BaseModel?如果我得到的 collection[0] 将是一个模型,而不是一个 BaseModel,那么我如何访问 Id 字段?
    • 您使用类型断言检查记录类型,然后访问该字段。例如,m := Records[0].(*User); println(m.Id);
    • 问题是您需要知道插入到Records 数组中的确切类型。如果您确实使用BaseModel 键入断言,但存储的实际上是User,则断言失败。 User is-not-a BaseModel。示例:play.golang.org/p/cnLnVpKTNk
    • 是的。如果您希望所有记录都有一个标识符,您可以使用Model 接口来实现它,例如。
    【解决方案2】:

    模型结构不是用户结构类型。
    即使嵌入模型,用户也不能表现模型。

    这种情况下,你可以使用如下界面。
    http://play.golang.org/p/Hh0zIT9yFC

    包主 导入“fmt” 类型模型接口 { GetID() 单位 } 类型 BaseModel 结构 { 标识单位 } func (m BaseModel) GetID() uint { 返回 m.Id } 类型集合结构{ 记录[]模型 } 类型用户结构{ *基础模型 名称字符串 } func (u 用户) GetName() 字符串 { 返回你的名字 } 功能主要(){ 用户 := User{&BaseModel{1}, "Jon"} uc := &Collection{[]Model{user}} u := uc.Records[0].(用户) fmt.Println(u.GetID()) fmt.Println(u.GetName()) }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-24
      • 1970-01-01
      • 2020-05-20
      • 2016-09-18
      相关资源
      最近更新 更多