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
被接受的任何地方使用Person
或Politician
,但是您也可以实现其他接口。
使用你的方法,你将被限制为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})