Go Reflection Values
Reflection values are handles that can read and change a value while the program runs. A handle can also run a method by naming it as a string.
Setting a field
The handle starts from the address of the struct. SetInt writes 150 into the Pages field.
package main
import (
"fmt"
"reflect"
)
type Book struct {
Title string
Pages int
}
func main() {
b := Book{Title: "Go", Pages: 100}
fmt.Println(b.Pages)
reflect.ValueOf(&b).Elem().Field(1).SetInt(150)
fmt.Println(b.Pages)
}Asking CanSet
The handle from a pointer can set the field. The handle from a plain copy cannot set it.
package main
import (
"fmt"
"reflect"
)
type Book struct {
Title string
Pages int
}
func main() {
b := Book{Title: "Go", Pages: 100}
fmt.Println(reflect.ValueOf(&b).Elem().Field(1).CanSet())
fmt.Println(reflect.ValueOf(b).Field(1).CanSet())
}A write that panics
This program builds the handle from a plain copy. The SetInt call panics and the program stops.
package main
import (
"fmt"
"reflect"
)
type Book struct {
Title string
Pages int
}
func main() {
b := Book{Title: "Go", Pages: 100}
reflect.ValueOf(b).Field(1).SetInt(150)
fmt.Println(b.Pages)
}Calling a method by name
MethodByName looks the method up as a string. Call runs it with no arguments and returns the answer.
package main
import (
"fmt"
"reflect"
)
type Book struct {
Title string
Pages int
}
func (b Book) Summary() string {
return fmt.Sprintf("%s has %d pages", b.Title, b.Pages)
}
func main() {
b := Book{Title: "Go", Pages: 120}
out := reflect.ValueOf(b).MethodByName("Summary").Call(nil)
fmt.Println(out[0].String())
}Example
package main
import (
"fmt"
"reflect"
)
type Book struct {
Title string
Pages int
}
func raise(v any, name string, value int64) {
reflect.ValueOf(v).Elem().FieldByName(name).SetInt(value)
}
func main() {
b := Book{Title: "Go", Pages: 100}
fmt.Println(b.Pages)
raise(&b, "Pages", 180)
fmt.Println(b.Pages)
}Key points
- SetInt writes a new value into an int field.
- A field must be addressable before a handle can set it.
- CanSet reports whether a handle can change its value.
- Setting an unaddressable value panics at run time.
- MethodByName finds a method from its name string.
- Call runs the method and returns its results in a slice.
In this example, raise takes a struct pointer, a field name, and a new value. It finds the field by name through reflection. It then sets the field to 180 and main prints the new count.
Note
Passing a pointer to a struct makes its fields addressable.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Go Playground
Exercise
What must a struct value have before reflection can set its fields?