I started learning golang a couple of days ago and found reflect.Valueof() and Value.Elem() quite confusing. What is the difference between this two function/methods and how to use them correctly?
Both function/methods return a Value, and according to the go doc
ValueOf returns a new Value initialized to the concrete value stored in the interface i. ValueOf(nil) returns the zero Value.
Elem returns the value that the interface v contains or that the pointer v points to. It panics if v's Kind is not Interface or Ptr. It returns the zero Value if v is nil.
I found this code from a post on stackoverflow but still don't understand when to use .Elem()
func SetField(obj interface{}, name string, value interface{}) error {
// won't work if I remove .Elem()
structValue := reflect.ValueOf(obj).Elem()
structFieldValue := structValue.FieldByName(name)
if !structFieldValue.IsValid() {
return fmt.Errorf("No such field: %s in obj", name)
}
if !structFieldValue.CanSet() {
return fmt.Errorf("Cannot set %s field value", name)
}
structFieldType := structFieldValue.Type()
// won't work either if I add .Elem() to the end
val := reflect.ValueOf(value)
if structFieldType != val.Type() {
return fmt.Errorf("Provided value %v type %v didn't match obj field type %v",val,val.Type(),structFieldType)
}
structFieldValue.Set(val)
return nil
}
reflect.ValueOf()
is a function, think of it as the entry point to reflection. When you have a "non-reflection" value, such as astring
orint
, you can usereflect.ValueOf()
to get areflect.Value
descriptor of it.Value.Elem()
is a method ofreflect.Value
. So you can only use this if you already have areflect.Value
. You may useValue.Elem()
to get the value (reflect.Value
) pointed by the value wrapped by the originalreflect.Value
. Note that you may also usereflect.Indirect()
for this. There's another "use case" forValue.Elem()
, but it's more "advanced", we return to it at the end of the answer.To "leave" reflection, you may use the general
Value.Interface()
method, which returns you the wrapped value as aninterface{}
.For example:
This will output (try it on the Go Playground):
For a great introduction to Go's reflection, read The Go Blog: The Laws of Reflection. Although if you're just starting with Go, I'd focus on other things and leave reflection for a later adventure.
Another use case for
Value.Elem()
This is kind of an advanced topic, so don't freak out if you don't understand it. You don't need to.
We saw how
Value.Elem()
can be used to "navigate" when a pointer is wrapped in thereflect.Value
. Doc ofValue.Elem()
says:So if
reflect.Value
wraps an interface value,Value.Elem()
may also be used to get the concrete value wrapped in that interface value.Interfaces in Go is its own topic, for the internals, you may read Go Data Structures: Interfaces by Russ Cox. Again, not necessarily a topic for Go starters.
Basically whatever value you pass to
reflect.ValueOf()
, if it's not already an interface value, it will be wrapped in aninterface{}
implicitly. If the passed value is already an interface value, then the concrete value stored in it will be passed as ainterface{}
. This second "use case" surfaces if you pass a pointer to interface (which is otherwise very rare in Go!).So if you pass a pointer to interface, this pointer will be wrapped in an
interface{}
value. You may useValue.Elem()
to get the pointed value, which will be an interface value (not a concrete value), and usingValue.Elem()
again on this will give you the concrete value.This example illustrates it:
Try it on the Go Playground.