2015-10-06 42 views
3

我创建了一个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}} 

我怎样才能让记录结构接受实施Model结构类型?

回答

5

你有两个选择:

  • 将另一个集合类型
  • 使用接口,而不是

实现单独收集像UserCollectionBarCollectionFooCollection是,如果一个选项你没有太多的foos和酒吧。

另一种方法是为使用通用空接口类型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虚拟方法。这个虚拟方法就是为了区分接口和空接口,所以你不能把整数值或字符串代替实际的模型到集合中。

+0

但在你的例子中,虽然我可以将BaseModel存储到记录中,但我怎样才能再次取回这些BaseModel?如果我得到的集合[0]是Model,而不是BaseModel,那么我如何访问Id字段? –

+0

您使用类型断言检查记录类型,然后访问该字段。例如,'m:= Records [0]。(* User);的println(m.Id);'。 – nemo

+0

问题是你需要知道在'Records'数组中插入的确切类型。如果你用'BaseModel'键入断言,但是存储的实际上是'User',断言失败。 'User'不是'BaseModel'。例如:https://play.golang.org/p/cnLnVpKTNk –

3

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

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

 
    package main 

    import "fmt" 

    type Model interface { 
     GetID() uint 
    } 

    type BaseModel struct { 
     Id uint 
    } 

    func (m BaseModel) GetID() uint { 
     return m.Id 
    } 

    type Collection struct { 
     Records []Model 
    } 

    type User struct { 
     *BaseModel 
     Name string 
    } 

    func (u User) GetName() string { 
     return u.Name 
    } 

    func main() { 
     user := User{&BaseModel{1}, "Jon"} 
     uc := &Collection{[]Model{user}} 
     u := uc.Records[0].(User) 
     fmt.Println(u.GetID()) 
     fmt.Println(u.GetName()) 
    }