I'm practicing reflections using go and I'm trying to achieve the following,
to have a struct type, with a field that is a pointer to a slice of strings.
now that pointer is nil, i want to create the slice, add a value and set that pointer in the struct to point to the newly created slice, and to do all of that using reflections.
I created the following sample code to demonstrate what I'm doing:
package main
import (
"log"
"reflect"
)
type UserInfo struct {
Name string
Roles *[]string
UserId int
}
func main() {
var myV UserInfo
myV.Name="moshe"
myV.UserId=5
v := reflect.ValueOf(&myV.Roles)
t := reflect.TypeOf(myV.Roles)
myP := reflect.MakeSlice(t.Elem(),1,1)
myP.Index(0).SetString("USER")
v.Elem().Set(reflect.ValueOf(&myP)) <-- PANIC HERE
log.Print(myV.Roles)
}
this panics the message
panic: reflect.Set: value of type *reflect.Value is not assignable to type *[]string
of course the slice does not create a pointer so if i do this:
v.Elem().Set(myP.Convert(v.Elem().Type()))
I get
panic: reflect.Value.Convert: value of type []string cannot be converted to type *[]string
but when I try to convert the address with
v.Elem().Set(reflect.ValueOf(&myP).Convert(v.Elem().Type()))
I get
panic: reflect.Value.Convert: value of type *reflect.Value cannot be converted to type *[]string
what am I still missing?
thanks!
You are attempting to set the value using a reflect.Value of a pointer to a reflect.Value, which is definitely not the same as a *[]string
Build the value up in steps and work your way outwards:
// create the []string, and set the element
slice := reflect.MakeSlice(t.Elem(), 1, 1)
slice.Index(0).SetString("USER")
// create the *[]string pointer, and set its value to point to the slice
ptr := reflect.New(slice.Type())
ptr.Elem().Set(slice)
// set the pointer in the struct
v.Elem().Set(ptr)
https://play.golang.org/p/Tj_XeXNNsML
Related
We are using the openapi-generator to generate a go-gin-server. This generates models containing properties of type *interface{} eg.
type Material struct {
Id *interface{} `json:"id,omitempty"`
Reference *interface{} `json:"reference,omitempty"`
}
If I have an instance of this struct, with nil pointers, how can these be set? I have tried the following:
theReturnId := "abc123"
material.Id = &theReturnId
This gives a compilation error of:
cannot use &theReturnId (value of type *string) as *interface{} value in assignment: *string does not implement *interface{} (type interface{} is pointer to interface, not interface)
theReturnId := "abc123"
*material.Id = theReturnId
This gives a runtime error that the pointer is nil.
I have tried a bunch of other things but to no avail. What am I missing here? Thanks!
You almost never need a pointer to an interface. You should be passing interfaces as values, but the underlying data though can still be a pointer.
You need to reconsider your design/code generation technique to not use such an approach as it is not idiomatic Go.
If you still want to use it, use a typed interface{} variable and take its address. The way you are doing in your example is incorrect as theReturnId is a string type taking its address would mean *string type, which cannot be assigned to *interface{} type directly as Go is a strongly typed language
package main
import "fmt"
type Material struct {
Id *interface{} `json:"id,omitempty"`
Reference *interface{} `json:"reference,omitempty"`
}
func main() {
newMaterial := Material{}
var foobar interface{} = "foobar"
newMaterial.Id = &foobar
fmt.Printf("%T\n", newMaterial.Id)
}
theReturnId := "abc123"
*material.Id = theReturnId
This gives a runtime error that the pointer is nil.
Because the field Id is set to its zero value, i.e.: nil, and dereferencing it (*material.Id) results in a run-time error. You can write a constructor for Material that initializes its *interface{} fields:
func NewMaterial() Material {
return Material {
new(interface{}),
new(interface{}),
}
}
Now, you can safely dereference the field Id:
material := NewMaterial()
theReturnId := "abc123"
*material.Id = theReturnId
I have a variable of type interface{} and I want to change the value of a field using reflection. How can I do it? Variable must be of type interface{} due to other requirements. If the variable isn't of type interface{} all works, otherwise code throws
reflect: call of reflect.Value.FieldByName on interface Value
my code
package main
import (
"fmt"
"reflect"
)
func main() {
a := struct {
Name string
}{}
// works
reflect.ValueOf(&a).Elem().FieldByName("Name").SetString("Hello")
fmt.Printf("%#v\n", a)
var b interface{}
b = struct {
Name string
}{}
// panics
reflect.ValueOf(&b).Elem().FieldByName("Name").SetString("Hello")
fmt.Printf("%#v\n", b)
}
The application must call Elem() twice to get the struct value:
reflect.ValueOf(&b).Elem().Elem().FieldByName("Name").SetString("Hello")
The first call Elem() dereferences the pointer to interface{}. The second call to Elem() gets the value contained in the interface.
With this change, the panic is reflect.Value.SetString using unaddressable value.
The application cannot set fields directly on the struct value contained in the interface because values contained in an interface are not addressable.
Copy the struct value to a temporary variable, set the field in the temporary variable and copy the temporary variable back to the interface.
var b interface{}
b = struct {
Name string
}{}
// v is the interface{}
v := reflect.ValueOf(&b).Elem()
// Allocate a temporary variable with type of the struct.
// v.Elem() is the vale contained in the interface.
tmp := reflect.New(v.Elem().Type()).Elem()
// Copy the struct value contained in interface to
// the temporary variable.
tmp.Set(v.Elem())
// Set the field.
tmp.FieldByName("Name").SetString("Hello")
// Set the interface to the modified struct value.
v.Set(tmp)
fmt.Printf("%#v\n", b)
Run it on the Go playground.
The interface b is initialized using the value of the anonymous struct, so b contains a copy of the struct, and the values are not addressable. Initialize b using a pointer:
var b interface{}
b = &struct {
Name string
}{}
reflect.ValueOf(b).Elem().FieldByName("Name").SetString("Hello")
So I have this:
v, ok := muxctx.Get(req, "req-body-map").(map[string]interface{})
the problem is that:
muxctx.Get(req, "req-body-map")
returns a pointer. I tried dereferencing the pointer like so:
(*(muxctx.Get(req, "req-body-map"))
but I get this:
Invalid indirect of '(muxctx.Get(req, "req-body-map"))' (type 'interface{}')
so I suppose since the Get method doesn't return a pointer, then I can't dereference it.
Pretty sure you want something like:
// You really want this to be two variables, lest you go mad.
// OK here is mostly to see whether the value exists or not, which is what
// presumably you're testing for. Get that out of the way before trying to
// get fancy with type coercion.
//
ptr, ok := muxctx.Get(req, "req-body-map")
... // Do other stuff (like your if test maybe)...
// Now coerce and deref. We coerce the type inside parens THEN we try to
// dereference afterwards.
//
v := *(ptr.(*map[string]interface{}))
A brief example of this general technique:
package main
import "fmt"
func main() {
foo := 10
var bar interface{}
bar = &foo
fmt.Println(bar)
foobar := *(bar.(*int))
fmt.Println(foobar)
}
$ ./spike
0xc00009e010
10
Finally, be really sure you have the type you want (using reflection if needbe) or risk the program panic'ing on a bad type coercion.
Get method is func (m *muxctx) Get(string) interface{}, return a value type is interface{}, if value is int(1) type is interface{}, if value is map[string]interface{} type return type also interface{}.
so ptr type is interface{} in ptr, ok := muxctx.Get(req, "req-body-map"), must convert interface{} ptr type a need type,example map[string]interface{}:ptr.(*map[string]interface{}), map ptr? ptr.(map[string]interface{}), map double ptr? ptr.(**map[string]interface{})
(*(muxctx.Get(req, "req-body-map")) convert code is invalid syntax, var i interface{}; *i,i type is interface{}, not use * remove pointer,must convert i to a ptr type, example:n := i.(*int); *n or m := i.(*map[string]interface{}); *m.
golang spce doc:
Type assertions
Type switches。
unsafe
Conversions
I wrote 3 similar functions to figure out a strange behavior of Go's pointer reflection.
package main
import (
"reflect"
"fmt"
)
var i interface{} = struct {}{} // i is an interface which points to a struct
var ptr *interface{} = &i // ptr is i's pointer
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x).Elem())
}
func main1() { // f is asking for interface? OK, I'll use the struct's interface
structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
f(structValue)
}
func main2() { // Error? Let me try the struct's pointer
structPtr := reflect.ValueOf(ptr).Elem().Interface()
f(structPtr)
}
func main3() { // Why this one could succeed after New() ?
typ := reflect.ValueOf(ptr).Elem().Elem().Type()
newPtr := reflect.New(typ).Elem().Addr().Interface()
f(newPtr)
}
func main() {
//main1() // panic: reflect: call of reflect.Value.Elem on struct Value
//main2() // panic: reflect: call of reflect.Value.Elem on struct Value
main3() // OK. WHY???
}
Only main3 is working, the other 2 would panic. Why?
The key difference of 3 is that it creates a New Value.
As to main2, I think ValueOf().Elem().Interface() has already reconstructed a interface which points at the struct{}{}, just don't understand why it would fail.
The value returned from reflect.ValueOf holds the concrete value stored in the argument. If the argument is nil, the zero reflect.Value is returned.
To put this another way, the reflect.Value and the interface passed to reflect.Value have the same underlying value.
The functions main1 and main2 will work as I think you expect if you f change to:
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x))
}
The argument to f in main3 is a *struct{}. The function f dereferences the pointer (with the call to Elem()) and prints the reflect value for the struct{}.
One point that might be confusing is that reflect.ValueOf(ptr).Elem().Elem().Interface() and reflect.ValueOf(ptr).Elem().Interface() return an interface with the same concrete value.
The expression reflect.ValueOf(ptr).Elem() is the reflect value corresponding to i. The call to Interface() on this value returns an interface with the concrete value in i.
The expression reflect.ValueOf(ptr).Elem().Elem() is the reflect value corresponding to i's concrete value. The call to Interface() on this value returns an interface containing that concrete value.
I'm trying to set struct.field = &otherStruct. However, I have to use reflection, and otherStruct is of type interface{}.
The error I'm getting is:
reflect.Set: value of type main.StructB is not assignable to type *main.StructB
struct is known. The (real) type of otherStruct is not known, but it is guaranteed, that the assignment is safe (the struct type is identical).
Code:
type StrucA struct {
Field *StrucB
}
type StrucB struct {}
func main() {
a := StrucA{}
var b interface{} = StrucB{}
//above is set
// Target: Set a.Field = &b
reflect.ValueOf(&a).Elem().FieldByName("Field").Set(reflect.ValueOf(b)) // reflect.Set: value of type main.StrucB is not assignable to type *main.StrucB
}
Playground:
https://play.golang.org/p/LR_RgfBzsxa
I have tested a lot of different stuff, but I'm unable to solve it.
You first need to allocate a pointer to the type of b, in order to have somewhere to copy the value. Once you have a pointer value, you can set that to Field in a:
field := reflect.New(reflect.TypeOf(b))
field.Elem().Set(reflect.ValueOf(b))
reflect.ValueOf(&a).Elem().FieldByName("Field").Set(field)
https://play.golang.org/p/6-GNSEq0tw3