嵌入式类型和结构的多态性

Jon*_*Jon 3 polymorphism struct go

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

type Model struct {
  Id uint
}

type Collection struct {
  Records []Model
}
Run Code Online (Sandbox Code Playgroud)

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

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

type User struct {
    *Model
    Name string
}
Run Code Online (Sandbox Code Playgroud)

并且由于a User不满足Model类型,我不能将它附加到这样的Collection结构:

user := User{&Model{1}, "Jon"}
uc := &Collection{[]User{user}}
Run Code Online (Sandbox Code Playgroud)

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

nem*_*emo 5

您有两种选择:

  • 制作另一种收藏类型
  • 请改用接口

实现单独收集像UserCollection,BarCollection,FooCollection是一个选项,如果你没有太多的Foo和酒吧.

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

type Collection struct {
    Records []interface{}
}
Run Code Online (Sandbox Code Playgroud)

这有许多缺点,例如每次访问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
}
Run Code Online (Sandbox Code Playgroud)

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