Assign a string to a struct via reflect [duplicate] - go

This question already has an answer here:
Update an attribute in a struct with reflection
(1 answer)
Closed 1 year ago.
I have a struct, where I wish to dynamically change a string to another string using reflect. My issue is that the new string is created on the stack, and therefore the Set() method panics.
This makes sense to me, but I don't know how to fix it. I'm not sure the easy way to declare a string as addressable or if there's a different reflection technique to use.
type MyStruct struct {
SomeField string
}
func main() {
myStruct := MyStruct{"initial"}
hello := "hello world"
field := reflect.ValueOf(myStruct).FieldByName("SomeField")
helloValue := reflect.ValueOf(hello)
fmt.Printf("hello is on the stack, canAddr is %v\n", helloValue.CanAddr())
// This will panic because canAddr is false
field.Set(helloValue)
}
https://play.golang.org/p/ghUgiQfKXhk

The go error is a bit of a misnomer. The problem is with the struct, not the string.
The problem is in this line:
field := reflect.ValueOf(myStruct).FieldByName("SomeField")
Calling ValueOf passes in a copy (of myStruct in this case). Since changing a copy won't change myStruct, then go panics (helpfully, if cryptically). See [the third law of reflection] (https://blog.golang.org/laws-of-reflection#TOC_8)
Changing this line to field := reflect.ValueOf(&myStruct).Elem().FieldByName("SomeField") fixes the error (note the & to take the address, and then Elem() to dereference)
Of course I only figure this out after posting the question but hopefully it will help someone else

Related

Obtaining an addressable copy of a reflect.Value

I want to add marshalling/unmarshalling to types that I accept, in a way similar JSON custom encoding/decoding. I have it all working great when the type implements a Marshal method (value receiver) and Unmarshal method (pointer receiver).
The Unmarshal method must obviously use a pointer receiver so that the new value is saved. I have been told that a Marshal method using a pointer (not value) receiver should also be allowed. The trouble with this is I am using a reflect.Value which is not always addressable.
Here's an edited extract of the code which panics:
var v reflect.Value // passed in parameter
t := v.Type()
pt := reflect.TypeOf(reflect.New(t).Interface())
if t.Implements(reflect.TypeOf((*Marshaler)(nil)).Elem()) {
str, err = v.Interface().(Marshaler).MarshalXXX()
// ... value receiver WORKS FINE
} else if pt.Implements(reflect.TypeOf((*Marshaler)(nil)).Elem()) {
str, err = v.Addr().Interface().(Marshaler).MarshalXXX()
// ptr receiver gives PANIC value is not addressable
I tried creating a copy of v, but the copy is also not addressable which makes no sense to me:
tmp := reflect.New(v.Type())
tmp.Addr().Set(v)
str, err = tmp.Interface().(Marshaler).MarshalXXX()
In case I have not explained this well here is an example on the Go Playground for you to try:
Also while I am here: Is there a better way to get the type of a pointer to a the type than in the assignment to pt above?
I found the answer. The problem was I was using Addr instead of Elem. Though that begs the question why Set worked, since the panic did not occur till the following line.
In summary, to create an addressable copy of a reflect.Value v do this:
tmp := reflect.New(v.Type()) // create zero value of same type as v
tmp.Elem().Set(v)
Please forgive me asking prematurely, but I had already spent 4 hours trying to solve the problem. For completeness here is the fix to my Go playground code in the question.

getting reflect.Value(&foo) from reflect.Value(foo)

the title of the question pretty much sums it up. I'm playing with reflections using Go, and I'm trying to get the address of what reflect.Value() is pointing at.
why?
I have a function that can receive a struct in two ways:
first.. this is the struct
type UserInfo struct {
Name string `json:"name"`
Roles *[]model.Role `json:"role"`
UserId int `json:"user_id" db:"id"`
}
one:
var userInfo types.UserInfo
myFunc(&userInfo)
with this method i'm good since since it's a pointer to a struct that has it's memory allocated
the 2nd method:
var userInfo *types.UserInfo
myFunc(userInfo)
so here if I do reflect.Value() it's a Nil Pointer.
i want to allocate that struct and to point userInfo to the new place.
now I can easily do that if I paste &userInfo as well
and perform:
myFunc(dst interface{}, dstAddr interface{})
{
v := reflect.ValueOf(dstAddr)
t := reflect.TypeOf(dst)
ptr := reflect.New(t.Type())
...
v.Elem().Set(ptr)
}
now I would except that reflect.ValueOf(dst).Addr() will be the same as reflect.ValueOf(&dst) but actually reflect.ValueOf(dst).CanAddr() returns false.
so.. is there a way to get reflect.ValueOf(&dst) while only having reflect.ValueOf(dst) ?
Whatever you pass to reflect.ValueOf() or any other function, a copy will be made.
That being said, reflect.Value(foo) cannot possibly give you back the address of the original foo, it could only give you back the address of the copy. To avoid further confusion, in this case Value.CanAddr() would return false, letting you know the address that could be returned using Value.Addr() would not be what most would expect, it wouldn't be a useful address.
As you indicated, you want to pass a single value, so pass &foo. Doing so you will be able to get the foo value pointed by &foo using Value.Elem().
Also note that the (wrapped) foo value you get by Value.Elem() will be addressable, since it was acquired from a reflect.Value wrapping &foo. So if the reflect.Value is not reflect.ValueOf(foo) but reflect.ValueOf(&foo).Elem(), you are able to get back (to) &foo.
See this example:
func main() {
var foo = 3
fmt.Println("Address:", &foo)
bar(&foo)
fmt.Println("After:", foo)
}
func bar(x interface{}) {
v := reflect.ValueOf(x)
v2 := v.Elem()
fmt.Println("Passed pointed value:", v2.Interface())
v2.Set(reflect.ValueOf(4))
fmt.Println("Address got from pointed value:", v2.Addr())
}
This will output (try it on the Go Playground):
Address: 0xc000080010
Passed pointed value: 3
Address got from pointed value: 0xc000080010
After: 4

"Cannot use variable of type []struct as []interface" while spreading [duplicate]

This question already has answers here:
slice of struct != slice of interface it implements?
(6 answers)
Closed 10 months ago.
Prototype function
func test(i ...interface{}) {
// Code here
}
Intended use
type foo struct {
// Fields
}
foos := []foo{
// foo1, foo2 ...
}
test(foos...) // ERROR
test(foos[1], foos[2], ...) // OK
Error
cannot use foos (variable of type []foos) as []interface{} value in argument to test
Description
The intended use is to be used like the built-in function append().
https://golang.google.cn/pkg/builtin/#append
func append(slice []Type, elems ...Type) []Type
Although, as I've seen append() doesn't use interface{}, which is strange, since anywhere that I searched all people say to use interface{} when you don't know the type. But they don't.
Nope, append() uses a "build-in" type called Type, which apparently the docs say that it's a int. Although, I cannot use it. There isn't such type. And neither I would know how to use it if there was.
https://golang.google.cn/pkg/builtin/#Type
type Type int
So, I'm very confused here.
Questions
Why does the spread operator not work as intended? For example, in Javascript the spread operator just spreads the array into items. But in Golang it seems like it keeps the same array parameter type as it is but gives the compiler later an instruction to spread it. Which is odd.
Are we even able to make similar custom mechanisms like append() at all? Or am I a dummy and I'm using something wrong anyway?
I think that this is the issue that you are running into here.
https://github.com/golang/go/wiki/InterfaceSlice
I am not an expert in this but have hit this before, the "slice of empty interface" is not an interface and therefore cannot be replaced by any type which is the issue that you are having, it has to do with the memory structure being different. The above has a far better explanation than one that I can give.
You can typecast your typed slice to get what you need:
generic := make([]interface{}, 0)
for _, f := range foos {
generic = append(generic, f)
}
test(generic...) // works
Combining the two non-negative answers into what I feel is the best solution:
interfaceSlice := make([]interface{}, len(foos))
for i, v := range foos {
interfaceSlice[i] = v
}
test(interfaceSlice...)
Partially inspired by:
https://github.com/golang/go/wiki/InterfaceSlice#what-can-i-do-instead

Can't set field of a struct that is typed as an interface{}

I've been struggling with the reflect package. This code below does what I expect:
package main
import (
"reflect"
"log"
)
type Car struct {
Model string
}
type Person struct {
Name string
Cars []Car
}
func ModifyIt(parent interface{},fieldName string, val interface{}) {
slice := reflect.ValueOf(parent).Elem()
nth := slice.Index(0)
//row := nth.Interface() // this line causes errors
row := nth.Interface().(Person)
elem := reflect.ValueOf(&row).Elem()
field := elem.FieldByName(fieldName)
log.Println(field.CanSet())
}
func main() {
p := []Person{Person{Name:"john"}}
c := []Car{Car{"corolla"},Car{"jetta"}}
ModifyIt(&p,"Cars",&c)
}
However, if I replace the line row := nth.Interface().(Person) with row := nth.Interface(), that is I remove the type assertion, then I get the error:
panic: reflect: call of reflect.Value.FieldByName on interface Value
on line "field := elem.FieldByName(fieldName)
I've tried a bunch of other things the last few hours like trying to do reflect.TypeOf(), reflect.Indirect() etc... on some of the other variables but with no success.
I've read some other questions like these:
reflect: call of reflect.Value.FieldByName on ptr Value
Set a struct field with field type of a interface
Golang reflection: Can't set fields of interface wrapping a struct
They seem to suggest that I don't have a good understanding of how pointers or interfaces work.
So my question is, how do I go about setting the field of a struct when the struct is typed as an interface?
UPDATE
I posted a solution as an answer, but I have no confidence in whether it is the proper or safe way of doing things. I hope someone can explain, or post a better solution.
Try this:
func ModifyIt(slice interface{}, fieldName string, newVal interface{}) {
// Create a value for the slice.
v := reflect.ValueOf(slice)
// Get the first element of the slice.
e := v.Index(0)
// Get the field of the slice element that we want to set.
f := e.FieldByName(fieldName)
// Set the value!
f.Set(reflect.ValueOf(newVal))
}
Call it like this:
p := []Person{Person{Name: "john"}}
c := []Car{Car{"corolla"}, Car{"jetta"}}
ModifyIt(p, "Cars", c)
Note that the call passes the slices directly instead of using pointers to slices. The pointers are not needed and add extra complexity.
Run it on the Playground.
Out of sheer luck, I finally got something to work.
I pieced together a bunch of random things I read with very little rhyme or reason. I even tried reading the Laws of Reflection on the Golang site, but I don't think I have a good grasp of how it relates to why I couldn't set variables typed as interface{}. In general, I still don't understand what I did.
My solution below is littered with comments to indicate my confusion, and lack of confidence in whether I did things properly or safely.
package main
import (
"reflect"
"log"
)
type Car struct {
Model string
}
type Person struct {
Name string
Cars []Car
}
func ModifyIt(parent interface{},fieldName string, val interface{}) {
log.Println(parent)
slice := reflect.ValueOf(parent).Elem()
nth := slice.Index(0)
row := nth.Interface()
log.Println(nth.CanSet()) // I can set this nth item
// I think I have a to make a copy, don't fully understand why this is necessary
newitem := reflect.New(reflect.ValueOf(row).Type())
newelem := newitem.Elem()
field := newelem.FieldByName(fieldName)
// I need to copy the values over from the old nth row to this new item
for c:=0; c<nth.NumField(); c++ {
newelem.Field(c).Set(reflect.Indirect(nth.Field(c)))
}
// now I can finally set the field for some reason I don't understand
field.Set(reflect.ValueOf(val).Elem())
// now that newitem has new contents in the field object, I need to overwrite the nth item with new item
// I don't know why I'm doing it, but I'll do it
// I also don't fully understand why I have to use Indirect sometimes, and not other times...it seems interchangeable with ValueOf(something).Elem(), I'm confused....
nth.Set(reflect.Indirect(newitem))
}
func main() {
p := []Person{Person{Name:"john"}}
c := []Car{Car{"corolla"},Car{"jetta"}}
ModifyIt(&p,"Cars",&c)
// now parent is up to date, although I have no idea how I got here.
log.Println(p)
}
If anyone can post a better answer that clears up my confusion, that will be great. I've been having a really hard time learning golang.

Is it possible to store a Type in a map and use it later to instantiate an object in Go lang? [duplicate]

This question already has answers here:
Instance new Type (Golang)
(2 answers)
Closed 5 years ago.
I am new to Go and I have this problem. I need to make a kind of "dispatcher" that will receive a string and return a type to be instantiated based on the string. For example:
AnimalType := mymap["animal"]
newAnimal := new(AnimalType)
Is there a way to do so?
Thanks in advance.
You can do this with the reflect package, though it should be noted that eventually you have to know the concrete type to really do much with it.
EDIT: LET IT BE KNOWN. This is a very BAD idea in the first place, and if you are doing this, you should probably rethink things. Go is a statically typed language, and unless you REALLY need to use the reflect package, you should stay away from it if possible. Even then, in most cases, this has already been done for you. Take, for instance, the JSON Marshal/Unmarshaller. At its core, they do some nasty reflection stuff, but it is already taken care of for you, just use it.
It is important to note that the type assertions (the .(*Thing1) lines) will panic if it isn't the right type. See https://tour.golang.org/methods/15
Test on playground: https://play.golang.org/p/DhiTnCVJi1
package main
import (
"fmt"
"reflect"
)
type Thing1 bool
type Thing2 int
type Thing3 struct {
Item string
}
func main() {
m := map[string]reflect.Type{}
var t1 Thing1
var t2 Thing2
var t3 Thing3
m["thing1"] = reflect.TypeOf(t1)
m["thing2"] = reflect.TypeOf(t2)
m["thing3"] = reflect.TypeOf(t3)
// later on
// thing1
newT1Value := reflect.New(m["thing1"])
// you use * here because a pointer to a boolean type isn't useful
newT1 := *newT1Value.Interface().(*Thing1) // cast to concrete type
fmt.Printf("T1: %v\n", newT1)
// thing2
newT2Value := reflect.New(m["thing2"])
// you use * here because a pointer to an int type isn't useful
newT2 := *newT2Value.Interface().(*Thing2)
fmt.Printf("T2: %v\n", newT2)
// thing3
newT3Value := reflect.New(m["thing3"])
// you can choose to use * or not here. Pointers to structs are actually useful
newT3 := newT3Value.Interface().(*Thing3)
newT3.Item = "Hello world"
fmt.Printf("T3: %#v\n", newT3)
}

Resources