How come this works:
slice := make([]string, 0, 10)
sliceptr := &slice
this too:
sliceptr := &[]string{"foo","bar","baz"}
But this doesn't:
sliceaddrval := reflect.ValueOf([]string{"foo","bar","baz"}).Addr()
It panics with: reflect.Value.Addr of unaddressable value
EDIT: Overall what I'm trying to do is take a struct that is of an unknown type, make a slice of structs of that type and return a pointer to it (I'm using github.com/jmoiron/modl which requires a pointer to slice to populate with results from a SQL query).
reflect.Value
takes an interface{}
, and an interface{}
to a value can't be used to change the original. Otherwise, you could end up with code changing data in your struct
when you didn't even intend to pass it a pointer. (Or, in this case, changing the length of a slice that was passed by value.) So if you take the address you'd have to do it before the ValueOf
.
To make a pointer to a slice that you can to pass to a package that will append
to it (like modl
or Google App Engine GetMulti
), you'd use something like http://play.golang.org/p/1ZXsqjrqa3, copied here:
package main
import (
"fmt"
"reflect"
)
type row struct { i, j int }
func main() {
aRow := row{}
valueType := reflect.ValueOf(aRow).Type()
slicePtrVal := reflect.New(reflect.SliceOf(valueType))
slicePtrIface := slicePtrVal.Interface()
getQueryResults(slicePtrIface)
fmt.Println(slicePtrIface)
}
// standing in for `modl` or whatever populates the slice
func getQueryResults(slicePtr interface{}) {
sPtr := slicePtr.(*[]row)
(*sPtr) = append((*sPtr), row{1,3})
}
Appending to a slice in a reflect.Value
yourself takes another few lines of reflect
, but it sounds like the package you're working with takes care of that part for you. For general info, code to do the append is at http://play.golang.org/p/m3-xFYc6ON and below:
package main
import (
"fmt"
"reflect"
)
type row struct { i, j int }
func main() {
aRow := row{}
// make a pointer to an empty slice
rowType := reflect.ValueOf(aRow).Type()
slicePtrVal := reflect.New(reflect.SliceOf(rowType))
slicePtrIface := slicePtrVal.Interface()
// append a zero row to it
rowVal := reflect.Zero(rowType)
sliceVal := reflect.Indirect(slicePtrVal)
sliceVal.Set(reflect.Append(sliceVal, rowVal))
fmt.Println(slicePtrIface)
}