Golang mutate a struct's field one by one using reflect - go

I have a struct like this:
type User struct {
Name string
UID int
Bio string
}
I have a given instantiated struct, and I want to loop through the fields in that object and modify them one by one.
This is what I have so far
user := User{
Name: "Test",
UID: 1,
Bio: "Test bio",
}
reflectVal := reflect.ValueOf(user)
numFields := reflectVal.NumField()
for i := 0; i < numFields; i++ {
fieldType := reflect.TypeOf(reflectVal.Field(i))
reflectVal.Field(i).Set(reflect.Zero(fieldType))
...
}
But I'm getting this error:
panic: reflect: reflect.Value.Set using unaddressable value
Is there a way to do this?

The reflect value is not addressable. Fix by creating the reflect value from a pointer to the struct.
reflectVal := reflect.ValueOf(&user).Elem()
Use the following statement to get the field's type. The code in the question gets the type of the reflect.Value, not the type of the value contained within the reflect.Value.
fieldType := reflectVal.Field(i).Type()
Run it on the Go Playground.

Related

Assigning to type definition using reflection in Go

I have setup a type called Provider that defines an integer:
type Provider int
func (enum *Provider) Scan(raw interface{}) error {
*enum = Provider(int(raw))
}
If I create an object, Foo, with a Provider field, like this:
type Foo struct {
Code Provider
Value string
}
foo := &Foo {
Code: Provider(0),
Value: "derp",
}
var scnr sql.Scanner
scannerType := reflect.TypeOf(&scnr).Elem()
tType := reflect.TypeOf(foo)
tField := tType.Field(0)
fmt.Printf("Field %s, of type %s, kind %s\n",
tField.Name, tField.Type, tField.Type.Kind())
When I run this code, I get that the field is of type Provider and its Kind is int. However, I cannot assign an int to a Provider using reflection because this will fail:
getInteger() interface{} {
return 1
}
fValue := reflect.ValueOf(foo).Elem()
vField := fValue.Field(0)
vField.Set(reflect.ValueOf(getInteger())) // panic: reflect.Set: value of type int is not assignable to type Provider
The normal solution to this would be to do reflect.ValueOf(Provider(getInteger().(int))), however, this won't work because vField is set inside of a loop that iterates over a structure's fields and therefore will have a different type. Essentially, I would like a way to detect that vField is a definition of int (ie. Provider) rather than an int, itself; so I could use reflection to cast the integer value to Provider when I set it.
Is there a way I can make this work?
The kind and type are not identical terms. Kind of both int and Provider is int because Provider has int as its underlying type. But the type Provider is not identical to int. What you have is a type definition, but not a type alias! Those are 2 different things. See Confused about behavior of type aliases for details.
The type of Foo.Code field is Provider, you can only assign a value of type Provider to it:
vField.Set(reflect.ValueOf(Provider(1)))
This works.
Note that reflection or not, you can't assign int to Foo.Code:
var i int = 3
var foo Foo
foo.Code = i // Error!
The above has compile time error:
error: cannot use i (variable of type int) as type Provider in assignment
What may be confusing is that using a constant works:
var foo Foo
foo.Code = 3 // Works!
This is because 3 is an untyped constant representable by a value of type Provider, so the constant will be converted to Provider.
I ended up using the Convert function in conjunction with the Assignable function to do my check:
// Get value to assign and its type
vValue := reflect.ValueOf(getInteger())
tValue := vValue.Type()
// Check if the field can be assigned the value; if it can then do so
// Otherwise, check if a conversion can be assigned
vType := vField.Type()
if tValue.AssignableTo(vType) {
vField.Set(vValue)
} else if vValue.CanConvert(vType) {
vField.Set(vValue.Convert(vType))
}
This fixed my issue.

go when to use & or not?

I am confused whether to use a & with go when declaring a variable and init with a struct
say we have a struct wrapper
type HttpResult struct {
Status int32 `json:"status"`
Msg string `json:"msg"`
Data interface{} `json:"data,omitempty"`
}
and a struct defining the user model
type OmUser struct {
Id primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Name string `json:"name"`
Password string `json:"password"`
Email string `json:"email"`
}
And the following declaring seems give the same result:
myOmUser := OmUser{ //note no & sign here
Name: "Tony",
Password: "mypass",
Email: "tony#foo.com"
}
httpResult := &HttpResult{
Status: 0,
Msg: "ok",
Data: myOmUser,
}
js, _ := json.Marshal(httpResult)
fmt.Println(js)
Or
myOmUser := &OmUser{ //note the & sign
Name: "Tony",
Password: "mypass",
Email: "tony#foo.com"
}
httpResult := &HttpResult{
Status: 0,
Msg: "ok",
Data: myOmUser,
}
js, _ := json.Marshal(httpResult)
fmt.Println(js)
so, when to use & and why?
In your particular example it doesn't make a difference.
But when we look at an example of using json.Unmarshal() it makes a bit more sense:
jsonBlob := []byte(`{"id": "1", "name": "bob", "password": "pass", "email", "hi#me.com"}`)
var newOmUser OmUser
err := json.Unmarshal(jsonBlob, &newOmUser)
if err != nil {
panic(err)
}
Here we declare the variable before hand, and then we use the & to pass a pointer to that variable into the Unmarshal function.
That means that the Unmarshal function can reach out and update that variable, even though it's declared outside of the function.
Without the &, the Unmarshal function would get a copy of the newOmUser variable, and it would leave the original newOmUser variable that we declared empty.
When it comes to pointers, my general rule of thumb is:
Don't use them unless you have to.
If you need to use any unmarshalling functions, you'll need them. There are lots of other functions that make use of them.
Here's a quick exercise that helps me understand a little more about pointers:
func uppercase(s string) {
s = strings.ToUpper(s)
fmt.Println(s)
}
// Same as the uppercase() function, but works with a pointer.
func uppercasePointer(s *string) {
*s = strings.ToUpper(*s)
fmt.Println(*s)
}
name := "bob"
uppercase(name) // prints 'BOB'
fmt.Println(name) // prints 'bob' - our variable was not changed
name2 := "bobpointer"
uppercasePointer(&name2) // prints 'BOBPOINTER'
fmt.Println(name2) // prints 'BOBPOINTER' - our variable was changed
When we call the uppercase(name) function, go makes a copy of the name variable and sends it to the uppercase function.
Whatever the function does to that copy that it received stays in the function. The original variable that we declared outside the function is not changed.
When we call the uppercasePointer(&name2) function, we are sending a pointer to the name2 variable we declared.
The function can use that pointer to reach out and update the name2 variable that we declared earlier.
At first, you might not see the point of pointers, but as you continue to use go, you will see that they help us solve some complex problems.
Empty interface type in Go can hold values of any type. Tour here.
So in your HttpResult.Data is an empty interface type. So you can assigne any type to it.
The difference between defining a variable with & is getting a pointer of that type. Tour here.
Those are obviously two types with two different functionalities in Go. But you can assign both to empty interface type variable because its accepting values of any type.
package main
import (
"fmt"
"reflect"
)
type OmUser struct {
}
func main() {
myOmUser := OmUser{}
myOmUser2 := &OmUser{}
fmt.Println(reflect.TypeOf(myOmUser)) //main.OmUser
fmt.Println(reflect.TypeOf(myOmUser2)) //*main.OmUser
}
For more details about &, read Go doc address operators
For an
operand x of type T, the address operation &x generates a pointer of
type *T to x. The operand must be addressable, that is, either a
variable, pointer indirection, or slice indexing operation; or a field
selector of an addressable struct operand; or an array indexing
operation of an addressable array. As an exception to the
addressability requirement, x may also be a (possibly parenthesized)
composite literal. If the evaluation of x would cause a run-time
panic, then the evaluation of &x does too.
fooA := &Foo{}
fooA has type *Foo.
fooB := Foo{}
fooB has type Foo.
https://tour.golang.org/moretypes/1
In practice, this means if you had a func that accepted type *Foo you could do either of the following...
func someFunc(f *Foo) {
// ...
}
fooA := &Foo{}
someFunc(fooA)
fooB := Foo{}
someFunc(&fooB)
So realistically, create whichever you need to be honest.

How to use reflect to set every field of struct to non-nil value in go

Suppose I have some type, and I want to instantiate a variable of this type, with every value non-nil.
type Event struct {
HappenedAtMs int64
ReceivedAtMs int64
FieldA *FieldAType
FieldB []*FieldBType
Here is what I am currently trying:
eventFields := reflect.TypeOf(Event{})
event := Event{}
for i := 0; i < eventFields.NumField(); i++ {
nonEmptyType := reflect.New(eventFields.Field(i).Type).Elem()
reflect.ValueOf(&event).Elem().Field(i).Set(nonEmptyType)
}
However, upon running this code, all the fields in the event variable are still set to nil. How can I achieve what I want?
The reflect package needs a pointer to the struct for it to be able to set its fields. The fields also need to be exported which you can check against using the CanSet method.
To initialize a pointer type with reflect you can simply do reflect.New(T.Elem()). To initialize a map, a slice, a func, or a chan type to non-nil you can use the MakeMap, MakeSlice, MakeFunc, and MakeChan functions respectively. To initialize an interface type to non-nil you can create an anonymous struct type, using reflect.StructOf, with a single embedded field of the target interface type, by embedding the interface type the struct type automatically satisfies the interface and an instance of it can be used to set the field to non-nil.
event := Event{}
rv := reflect.ValueOf(&event).Elem()
for i := 0; i < rv.NumField(); i++ {
if f := rv.Field(i); isNilable(f) && f.IsNil() && f.CanSet() {
switch f.Kind() {
case reflect.Ptr:
f.Set(reflect.New(f.Type().Elem()))
case reflect.Slice:
f.Set(reflect.MakeSlice(f.Type(), 0, 0))
case reflect.Interface:
sf := reflect.StructField{
Name: f.Type().Name(),
Type: f.Type(),
Anonymous: true,
}
rt := reflect.StructOf([]reflect.StructField{sf})
f.Set(reflect.New(rt).Elem())
// TODO handle the rest of nilable types
}
}
}
https://play.golang.com/p/nQqvUIROqF-

Golang Reflection: Inspect a struct type definition to extract its properties without initialization

If I have the following declaration
type Foo struct {
bar string
}
Can I use reflection to inspect the properties on the declaration without initialising it?
keys := reflect.something(Foo)
for _, key := range keys {
fmt.Println(key) // "bar"
}
Use reflect.TypeOf to get the reflect.Type for Foo.
t := reflect.TypeOf(Foo{})
If you don't want to create a value of the type, then get the pointer type and "dereference" that type.
t := reflect.TypeOf((*Foo)(nil)).Elem()
The expression (*Foo)(nil) returns a nil pointer to the type. The Type.Elem method returns the pointed to type.
Iterate through the fields on the type. Type.NumField returns the number of fields on the type. Type.Field returns a StructField by field index.
for i := 0; i < t.NumField; i++ {
fmt.Println(t.Field(i).Name)
}
Run it on the playground.

Generic Programming in Go, Implicit generic type

I need Go to implicitly resolve my struct type, in order to do generic replacement of some attribute.
//must replace the attribute with attValue
func SetAttribute(object interface{}, attributeName string, attValue interface{}, objectType reflect.Type) interface{} {
/// works perfectly, but function SetAttribute needs to know Customer type to do the convertion
convertedObject := object.(Customer) // <-- Need to hard code a cast :(
// doesn't works... raise panic!
//convertedObject := object
value := reflect.ValueOf(&convertedObject).Elem()
field := value.FieldByName(attributeName)
valueForAtt := reflect.ValueOf(attValue)
field.Set(valueForAtt)
return value.Interface()
}
Please check out full example in the Go playground...
http://play.golang.org/p/jxxSB5FKEy
convertedObject is the value of what is in the object interface. Taking the address of that has no effect on the original customer. (and converted is probably a poor prefix for the name, since that is generated from a "type assertion", not a "type conversion")
If you use object directly, it panics, because you're then taking the address of the interface, not the customer.
You need to pass the address of the customer you want to modify to the function:
SetAttribute(&customer, "Local", addressNew, reflect.TypeOf(Customer{}))
You can also have your SetAttribute check if it's a pointer first:
if reflect.ValueOf(object).Kind() != reflect.Ptr {
panic("need a pointer")
}
value := reflect.ValueOf(object).Elem()
field := value.FieldByName(attributeName)
valueForAtt := reflect.ValueOf(attValue)
field.Set(valueForAtt)
return value.Interface()

Resources