golang:它的结构片!=它实现的接口片?

我有一个接口Model ,由struct Person实现。

为了得到一个模型实例,我有以下的帮助函数:

 func newModel(c string) Model { switch c { case "person": return newPerson() } return nil } func newPerson() *Person { return &Person{} } 

上面的方法允许我返回一个正确types的Person实例(以后可以用相同的方法轻松添加新的模型)。

当我试图做类似的事情来返回一个模型,我得到一个错误。 码:

 func newModels(c string) []Model { switch c { case "person": return newPersons() } return nil } func newPersons() *[]Person { var models []Person return &models } 

去抱怨: cannot use newPersons() (type []Person) as type []Model in return argument

我的目标是返回一个任何模型types的请求(无论是[]Person[]FutureModel[]Terminator2000 ,w / e)的[]FutureModel 。 我错过了什么,如何正确实施这样的解决scheme?

这与我刚刚回答的问题非常相似: https : //stackoverflow.com/a/12990540/727643

简短的回答是,你是正确的。 结构的一部分不等于结构实现的接口的一部分。

A []Person[]Model具有不同的内存布局。 这是因为它们的切片types具有不同的内存布局。 Model是一个界面值,这意味着在内存中它是两个字的大小。 一个字为types信息,另一个为数据。 Person是一个结构,它的大小取决于它所包含的字段。 为了从[]Person转换为[]Model ,您将需要遍历数组并为每个元素进行types转换。

由于这个转换是一个O(n)操作,并且会导致一个新的slice被创build,所以Go拒绝隐式执行它。 你可以用下面的代码明确地做到这一点。

 models := make([]Model, len(persons)) for i, v := range persons { models[i] = Model(v) } return models 

正如dskinner所指出的 ,你很可能需要一些指针,而不是一个指向片的指针。 通常不需要指向切片的指针。

 *[]Person // pointer to slice []*Person // slice of pointers 

也许这是你的返回types*[]Person ,它应该实际上是[]*Person以便引用该片的每个索引是对Person的引用,并且其中slice []本身就是一个引用到一个数组。

看看下面的例子:

 package main import ( "fmt" ) type Model interface { Name() string } type Person struct {} func (p *Person) Name() string { return "Me" } func NewPersons() (models []*Person) { return models } func main() { var p Model p = new(Person) fmt.Println(p.Name()) arr := NewPersons() arr = append(arr, new(Person)) fmt.Println(arr[0].Name()) } 

正如斯蒂芬已经回答了这个问题,你是一个初学者,我强调给予build议。

使用go的接口的一个更好的方法是不要有一个构造函数像其他语言(比如java)那样返回接口,而是要独立地为每个对象构造一个构造函数,因为它们隐含地实现了接口。

代替

 newModel(type string) Model { ... } 

你应该做

 newPerson() *Person { ... } newPolitician() *Politician { ... } 

与人和Politician都实施Model的方法。 您仍然可以在Model被接受的任何地方使用PersonPolitician ,但是您也可以实现其他接口。

使用你的方法,你将被限制为Model直到你手动转换到另一个接口types。

假设我有一个实现了Walk()方法的Person和一个Model实现了ShowOff() ,下面的代码不会直接工作:

 newModel("person").ShowOff() newModel("person").Walk() // Does not compile, Model has no method Walk 

但是,这将会:

 newPerson().ShowOff() newPerson().Walk() 

typesT和[] T是不同的types,不同的是他们的方法,即使在满足相同的接口。 IOW中,每个满足模型的types必须自己实现所有模型的方法 – 方法接收器可以只有一个特定的types。

正如其他人已经回答,[T]是一个独特的types。 我只想补充一点,一个简单的实用程序可以用来一般地转换它们。

 import "reflect" // Convert a slice or array of a specific type to array of interface{} func ToIntf(s interface{}) []interface{} { v := reflect.ValueOf(s) // There is no need to check, we want to panic if it's not slice or array intf := make([]interface{}, v.Len()) for i := 0; i < v.Len(); i++ { intf[i] = v.Index(i).Interface() } return intf } 

现在,你可以像这样使用它:

 ToIntf([]int{1,2,3})