I have an interface Model
, which is implemented by struct Person
.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person
, []FutureModel
, []Terminator2000
, w/e). What am I missing, and how can I properly implement such a solution?
Best Answer
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A
[]Person
and a[]Model
have different memory layouts. This is because the types they are slices of have different memory layouts. AModel
is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. APerson
is a struct whose size depends on the fields it contains. In order to convert from a[]Person
to a[]Model
, you will need to loop over the array and do a type conversion for each element.Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.