I'm having trouble calling a function which returns []interface{} and
converting or accessing those results as the underlying struct they're
supposed to be.
This came up while using mgo, the mongodb driver for go, but I realize
it's more of an issue of my understanding of go in general, so I'm
asking the question here.
Suppose I have several structs, one of which is defined as:
type Person struct {
FirstName string
LastName string
}
I also have a function which queries a database, and depending on the
parameter input, can return a Person, among other types of structs:
func DoQuery(collection string, query interface{}) (result
[]interface{}) {
// run the query and put the results into &result
return result
}
When I run it like this:
for _, person := range DoQuery(bson.M{"lastName": "Jones"}) {
fmt.Println(person)
}
I don't get back a Person struct as I expect, but a map object, like
this, for each person in the result set:
map[FirstName:Alex LastName:Jones]
If I try to access person.LastName or person.FirstName within the loop
above, the program won't compile, and I get this kind of error:
person.FirstName undefined (type interface {} has no field or method
FirstName)
After reading the section on reflection (
http://golang.org/doc/
articles/laws_of_reflection.html), I tried rewriting the loop this
way:
for _, person := range DoQuery(bson.M{"lastName": "Jones"}) {
p := reflect.ValueOf(&person).Elem()
for i := 0; i < p.NumField(); i++ {
fmt.Print(p.Field(i))
}
fmt.Println()
}
While that compiled, it gave me a runtime panic:
panic: result argument must be a slice address
And when I tried to take a slice, I started getting compiler errors:
invalid operation: person[x] (index of type interface {})
While I could avoid all this by making the return type of the
DoQuery() function to be (result []Person), it doesn't give me the
flexibility I want in terms of being able to pass different input
parameters to get different structs.
I also tried forcing the return type like this, but it wouldn't
compile:
var result []RelatedPerson
result = DoQuery("relatedPerson", bson.M{"lastName":
"Jones"})
for _, person := range result {
fmt.Println(person)
}
So what am I not getting about handling arrays of interface{}?