Without reflection it is possible to add multiple types to a list of type []interface{}. Like so:
package main
import "fmt"
func main() {
var foo []interface{}
foo = append(foo, "Test")
foo = append(foo, "Foo")
foo = append(foo, 10)
fmt.Printf("%v\n", foo)
}
Is this possible with reflection? I try the following but I get a panic saying: "panic: reflect.Set: value of type string is not assignable to type []interface {}"
package main
import (
"fmt"
"reflect"
)
func rf(inf interface{}) {
val := reflect.Indirect(reflect.ValueOf(inf))
field := val.FieldByName("Foo")
rslice := reflect.MakeSlice(reflect.SliceOf(field.Type()), 0, 5)
v := reflect.Indirect(reflect.ValueOf("Test"))
rslice = reflect.Append(rslice, v)
}
func main() {
var s struct {
Foo []interface{}
}
rf(&s)
fmt.Printf("%+v\n", s)
}
The Foo field is already of type []interface{}, so SliceOf is creating a [][]interface{}, which is what causes the error you see.
Remove the SliceOf, and then use field.Set(rslice) to set the new value back to the struct field.
func rf(inf interface{}) {
val := reflect.Indirect(reflect.ValueOf(inf))
field := val.FieldByName("Foo")
rslice := reflect.MakeSlice(field.Type(), 0, 5)
v := reflect.Indirect(reflect.ValueOf("Test"))
rslice = reflect.Append(rslice, v)
field.Set(rslice)
}
http://play.golang.org/p/gWK3-cP_MN
Related
I want to achieve polymorfism by passing a pointer to a slice of a speficic interface to a function, and update the slice inside of the function. It works quite well with interface{}
package main
import (
"fmt"
"strconv"
)
type valuer interface {
value() string
}
type myInt int
func (i myInt) value() string {
return strconv.Itoa(int(i))
}
func values(vals interface{}) {
res, ok := vals.(*[]myInt)
if !ok {
panic("wrong type")
}
*res = []myInt{1, 2, 3}
}
func main() {
var a []myInt
values(&a)
for _, b := range a {
fmt.Println(b.value())
}
}
Go Playground
However if I try to change interface{} to a pointer to a slice of a specific interface it does not work:
package main
import (
"fmt"
"strconv"
)
type valuer interface {
value() string
}
type myInt int
func (i myInt) value() string {
return strconv.Itoa(int(i))
}
func values(vals *[]valuer) {
*vals = []myInt{1, 2, 3}
}
func main() {
var a []myInt
values(&a)
for _, b := range a {
fmt.Println(b.value())
}
}
Go Playground
returning an error
./prog.go:19:8: cannot use []myInt literal (type []myInt) as type []valuer in assignment
./prog.go:24:9: cannot use &a (type *[]myInt) as type *[]valuer in argument to values
What am I doing wrong?
From the insights provided by #kostix, I can see that I cannot keep both -- a restriction of a non-empty interface, and a simplicity of passing a pointer of a slice of a concrete type. So if I do want to keep the output as a slice of non-empty interfaces, I can do something of this sort instead:
package main
import (
"fmt"
"strconv"
)
type valuer interface {
value() string
}
type myInt int
func (i myInt) value() string {
return strconv.Itoa(int(i))
}
func values() []valuer {
res := make([]valuer, 3)
c := []myInt{1, 2, 3}
for i, v := range c {
res[i] = v
}
return res
}
func main() {
a := values()
for _, b := range a {
fmt.Println(b.value())
}
}
Go Playground
It would keep api simpler to use, and allow polymorphism with non-empty interfaces for the output.
One inconvenience for the users with this approach, they will have to "unbox" members of the slice if they want to use methods of a concrete type that are not specified by the interface.
I'd like to get the value of all the fields in a struct that aren't empty. This works for simple primitives (string, int, etc.), but not for struct types such as sql.NullString.
Very simple example:
package main
import (
"database/sql"
"fmt"
"reflect"
)
func main() {
type fooT struct {
NullS sql.NullString
}
values := reflect.ValueOf(fooT{})
field := values.Field(0)
v := reflect.ValueOf(field)
iface := v.Interface().(sql.NullString)
fmt.Println(iface)
}
This gives a panic:
panic: interface conversion: interface is reflect.Value, not sql.NullString
I don't understand this, since the Interface method should return an interface{} (and not a reflect.Value) which I can then type assert (?)
First I thought I was maybe using type conversions only works for primitives, but a quick test script:
package main
import (
"database/sql"
"fmt"
)
func main() {
type fooT struct {
NullS sql.NullString
}
foo := fooT{NullS: sql.NullString{"It's an Aardvark!", true}}
var iface interface{}
iface = foo.NullS
fmt.Printf("%T -> %#v\n", iface, iface)
fmt.Printf("%T -> %#v -> %#v\n", iface.(sql.NullString), iface.(sql.NullString),
iface.(sql.NullString).Valid)
}
Reveals that this should work?
The full code I'm using:
package main
import (
"database/sql"
"fmt"
"reflect"
)
type fooT struct {
ID int64
Foo string
NullS sql.NullString
FooQ sql.NullString
}
func main() {
foo := fooT{
ID: 42,
NullS: sql.NullString{"Your mother was a hamster", true},
}
types := reflect.TypeOf(foo)
values := reflect.ValueOf(foo)
changed := ""
for i := 0; i < types.NumField(); i++ {
fieldType := types.Field(i)
field := values.Field(i)
switch field.Type().Kind() {
// Works
case reflect.String:
if field.String() != "" {
changed += fmt.Sprintf("<strong>%s</strong>: %v<br>\n",
fieldType.Name, field.String())
}
default:
switch field.Type().String() {
case "sql.NullString":
v := reflect.ValueOf(field)
// NullS: reflect.Value -> sql.NullString{String:"Your mother was a hamster", Valid:true}
iface := v.Interface()
fmt.Printf("%s: %T -> %#v\n",
fieldType.Name, iface, iface)
// panic: interface conversion: interface is reflect.Value, not sql.NullString
iface2 := v.Interface().(sql.NullString)
fmt.Printf("%s: %T -> %#v\n",
fieldType.Name, iface2, iface2)
}
}
}
fmt.Printf(changed)
}
I think the problem is that an extra reflect.ValueOf meant that you had a reflect.Value referring to another reflect.Value, not to the NullString. The way Printf formatted it kind of obscured that. It looks like values.Field(i) returns the reflect.Value you need. Here's your program minimally modified by taking out the ValueOf:
package main
import (
"database/sql"
"fmt"
"reflect"
)
type fooT struct {
ID int64
Foo string
NullS sql.NullString
FooQ sql.NullString
}
func main() {
foo := fooT{
ID: 42,
NullS: sql.NullString{"Your mother was a hamster", true},
}
types := reflect.TypeOf(foo)
values := reflect.ValueOf(foo)
changed := ""
for i := 0; i < types.NumField(); i++ {
fieldType := types.Field(i)
field := values.Field(i)
switch field.Type().Kind() {
// Works
case reflect.String:
if field.String() != "" {
changed += fmt.Sprintf("<strong>%s</strong>: %v<br>\n",
fieldType.Name, field.String())
}
default:
switch field.Type().String() {
case "sql.NullString":
iface := field.Interface()
fmt.Printf("%s: %T -> %#v\n",
fieldType.Name, iface, iface)
}
}
}
fmt.Printf(changed)
}
You may be able to simplify more by using a type switch to do most of the work, like so:
package main
import (
"database/sql"
"fmt"
"reflect"
)
type fooT struct {
ID int64
Foo string
NullS sql.NullString
FooQ sql.NullString
}
func main() {
foo := fooT{
ID: 42,
NullS: sql.NullString{"Your mother was a hamster", true},
}
values := reflect.ValueOf(foo)
changed := ""
for i := 0; i < values.NumField(); i++ {
v := values.Field(i)
f := v.Interface()
switch f := f.(type) {
case string:
fmt.Println("string:", f)
case sql.NullString:
fmt.Println("NullString:", f.Valid, f.String)
default:
fmt.Printf("%s: %v\n", v.Type(), f)
}
}
fmt.Printf(changed)
}
Can't get returning string value of a method called via reflection
panic: interface conversion: interface is []reflect.Value, not string
package main
import (
"reflect"
)
type API_EndPoint struct{}
func main() {
var ep API_EndPoint
s := reflect.ValueOf(&ep).MethodByName("EndPoint_X").Call([]reflect.Value{reflect.ValueOf(`foo bar`)})
v := reflect.ValueOf(s)
i := v.Interface()
a := i.(string)
println(a)
}
func (ep *API_EndPoint) EndPoint_X(params string) string {
return "this_is_a_string" + params
}
see this code in play.golang.org
.Call returns a slice of reflect.Value so to do what you're trying to do you need to do something like:
package main
import ("reflect")
type API_EndPoint struct {}
func main() {
var ep API_EndPoint
s := reflect.ValueOf(&ep).MethodByName("EndPoint_X").Call([]reflect.Value{reflect.ValueOf(`foo bar`)})
v := reflect.ValueOf(s)
i := v.Interface()
a := i.([]reflect.Value)[0].String() // Get the first index of the slice and call the .String() method on it
println(a)
}
func (ep *API_EndPoint) EndPoint_X( params string) string{
return "this_is_a_string " + params
}
https://play.golang.org/p/MtqCrshTcH
this_is_a_string foo bar
Not sure what you're trying to accomplish but that should work.
I want to use some external code that requires a pointer to a struct. At the point that the code is called, I have an interface variable.
When creating a pointer off of that variable, the pointer's type is interface{}* when I need it to be the pointer type of the struct's type.
Image the code in TestCanGetStructPointer does not know about the Cat class, and that it exists in some external package.
How can I cast it to this?
Here is a code sample:
import (
"reflect"
"testing"
)
type Cat struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{}
}
var somethingForCats = SomethingGeneric{getSomething: getSomeCat}
func TestCanGetStructPointer(t *testing.T) {
interfaceVariable := somethingForCats.getSomething()
pointer := &interfaceVariable
interfaceVarType := reflect.TypeOf(interfaceVariable)
structPointerType := reflect.PtrTo(interfaceVarType)
pointerType := reflect.TypeOf(pointer)
if pointerType != structPointerType {
t.Errorf("Pointer type was %v but expected %v", pointerType, structPointerType)
}
}
The test fails with:
Pointer type was *interface {} but expected *parameterized.Cat
#dyoo's example does work, but it relies on you to manually cast Dog and Cat.
Here's a bit of a convoluted/verbose example which avoids that constraint somewhat:
package main
import (
"fmt"
"reflect"
)
type Cat struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{name: "Fuzzy Wuzzy"}
}
var somethingForCats = SomethingGeneric{getSomething: getSomeCat}
func main() {
interfaceVariable := somethingForCats.getSomething()
castVar := reflect.ValueOf(interfaceVariable)
castVar.Convert(castVar.Type())
// If you want a pointer, do this:
fmt.Println(reflect.PtrTo(castVar.Type()))
// The deref'd val
if castVar.Type() != reflect.TypeOf(Cat{}) {
fmt.Printf("Type was %v but expected %v\n", castVar, reflect.TypeOf(&Cat{}))
} else {
fmt.Println(castVar.Field(0))
}
}
Playground Link
I found this thread: https://groups.google.com/forum/#!topic/golang-nuts/KB3_Yj3Ny4c
package main
import (
"fmt"
"reflect"
)
type Cat struct {
name string
}
//
// Return a pointer to the supplied struct via interface{}
//
func to_struct_ptr(obj interface{}) interface{} {
fmt.Println("obj is a", reflect.TypeOf(obj).Name())
// Create a new instance of the underlying type
vp := reflect.New(reflect.TypeOf(obj))
// Should be a *Cat and Cat respectively
fmt.Println("vp is", vp.Type(), " to a ", vp.Elem().Type())
vp.Elem().Set(reflect.ValueOf(obj))
// NOTE: `vp.Elem().Set(reflect.ValueOf(&obj).Elem())` does not work
// Return a `Cat` pointer to obj -- i.e. &obj.(*Cat)
return vp.Interface()
}
//
// Dump out a pointer ...
//
func test_ptr(ptr interface{}) {
v := reflect.ValueOf(ptr)
fmt.Println("ptr is a", v.Type(), "to a", reflect.Indirect(v).Type())
}
func main() {
cat := Cat{name: "Fuzzy Wuzzy"}
// Reports "*main.Cat"
test_ptr(&cat)
// Get a "*Cat" generically via interface{}
sp := to_struct_ptr(cat)
// *should* report "*main.Cat" also
test_ptr(sp)
fmt.Println("sp is",sp)
}
The following may help: http://play.golang.org/p/XkdzeizPpP
package main
import (
"fmt"
)
type Cat struct {
name string
}
type Dog struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{name: "garfield"}
}
func getSomeDog() interface{} {
return Dog{name: "fido"}
}
var somethings = []SomethingGeneric{
SomethingGeneric{getSomething: getSomeCat},
SomethingGeneric{getSomething: getSomeDog},
}
func main() {
for _, something := range somethings {
interfaceVariable := something.getSomething()
cat, isCat := interfaceVariable.(Cat)
dog, isDog := interfaceVariable.(Dog)
fmt.Printf("cat %v %v\n", cat, isCat)
fmt.Printf("dog %v %v\n", dog, isDog)
}
}
What is the way of printing "Foo" here? In this example, what prints is "string".
http://play.golang.org/p/ZnK6PRwEPp
type A struct {
Foo string
}
func (a *A) PrintFoo() {
fmt.Println("Foo value is " + a.Foo)
}
func main() {
a := &A{Foo: "afoo"}
val := reflect.Indirect(reflect.ValueOf(a))
fmt.Println(val.Field(0).Type().Name())
}
You want val.Type().Field(0).Name. The Field method on reflect.Type will return a struct describing that field, which includes the name, among other information.
There is no way to retrieve the field name for a reflect.Value representing a particular field value, since that is a property of the containing struct.
I think the better way to get the fields' name in the struct is
func main() {
a := &A{Foo: "afoo"}
val := reflect.ValueOf(a).Elem()
for i:=0; i<val.NumField();i++{
fmt.Println(val.Type().Field(i).Name)
}
}
There are two tips:
use .Elem() after you reflect.ValueOf(a), because in your case, a is a pointer.
val.Field(i).Type().Name is totally different from val.Type().Field(i).Name. The latter one can get the name of the field in the struct
Hope that it is helpful..
If you want to have a look at more cases, please check my 2mins article
You need to Get the Field of the Type Definition not of the Value.
http://play.golang.org/p/7Bc7MJikbJ
package main
import "fmt"
import "reflect"
type A struct {
Foo string
}
func (a *A) PrintFoo() {
fmt.Println("Foo value is " + a.Foo)
}
func main() {
a := &A{Foo: "afoo"}
val := reflect.Indirect(reflect.ValueOf(a))
fmt.Println(val.Type().Field(0).Name)
}
With the new Names method of the structs package it's even more easier:
package main
import (
"fmt"
"github.com/fatih/structs"
)
type A struct {
Foo string
Bar int
}
func main() {
names := structs.Names(&A{})
fmt.Println(names) // ["Foo", "Bar"]
}
You can also use https://github.com/fatih/structs
// Convert the fields of a struct to a []*Field
fields := s.Fields()
for _, f := range fields {
fmt.Printf("field name: %+v\n", f.Name())
}
package main
import "fmt"
import "reflect"
type A struct {
Foo string
}
func (a *A) PrintFoo() {
fmt.Println("Foo value is " + a.Foo)
}
func main() {
a := &A{Foo: "afoo"}
//long and bored code
t := reflect.TypeOf(*a)
if t.Kind() == reflect.Struct {
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Name)
}
} else {
fmt.Println("not a stuct")
}
//shorthanded call
fmt.Println(reflect.TypeOf(*a).Field(0).Name)//can panic if no field exists
}
You can use this function, which takes the struct as the first parameter, and then its fields. It returns the map type, which is convenient to use
If you use fields from another structure, nothing will happen
If you try to use a different type, it will cause panic
Note that the field has an ordinal number according to the list (starting from 0). All fields in the structure must start with uppercase
func GetStructFieldName(Struct interface{}, StructField ...interface{}) (fields map[int]string) {
fields = make(map[int]string)
s := reflect.ValueOf(Struct).Elem()
for r := range StructField {
f := reflect.ValueOf(StructField[r]).Elem()
for i := 0; i < s.NumField(); i++ {
valueField := s.Field(i)
if valueField.Addr().Interface() == f.Addr().Interface() {
fields[i] = s.Type().Field(i).Name
}
}
}
return fields
}
Full example and playground
package main
import (
"fmt"
"reflect"
)
type Example struct {
Apple bool
Pear int
}
func GetStructFieldName(Struct interface{}, StructField ...interface{}) (fields map[int]string) {
fields = make(map[int]string)
for r := range StructField {
s := reflect.ValueOf(Struct).Elem()
f := reflect.ValueOf(StructField[r]).Elem()
for i := 0; i < s.NumField(); i++ {
valueField := s.Field(i)
if valueField.Addr().Interface() == f.Addr().Interface() {
fields[i] = s.Type().Field(i).Name
}
}
}
return fields
}
func main() {
e := Example{}
names := GetStructFieldName(&e, &e.Apple, &e.Pear)
fmt.Println(names)
fmt.Println(names[0], names[1])
for i := range names {
fmt.Println(names[i])
}
/* Output:
map[0:Apple 1:Pear]
Apple Pear
Apple
Pear
*/
}