反射的另一个重要类型就是 reflect.Value,我们可以通过调用 reflect.ValueOf 来获取,同样的,对于 Value 类型官方也提供了很多方法来获取相关的信息,但不是所有的方法对任何的类型都是通用的,如果对不适用的场景调用就会发生 panic
CanSet 用来判断底层的值是否是可以修改的,如果是可以修改的那么就可以调用 Set 来进行修改,需要注意的是通过reflect.ValueOf直接返回的都是只读的
package main
import "fmt"
import "reflect"
func main() {
n := 123
p := &n
vp := reflect.ValueOf(p)
fmt.Println(vp.CanSet(), vp.CanAddr()) // false false
vn := vp.Elem() // get the value referenced by vp
fmt.Println(vn.CanSet(), vn.CanAddr()) // true true
vn.Set(reflect.ValueOf(789)) // <=> vn.SetInt(789)
fmt.Println(n) // 789
}
对于 struct 中非导出的字段我们也是不能进行修改的
package main
import "fmt"
import "reflect"
func main() {
var s struct {
X interface{} // an exported field
y interface{} // a non-exported field
}
vp := reflect.ValueOf(&s)
// If vp represents a pointer. the following
// line is equivalent to "vs := vp.Elem()".
vs := reflect.Indirect(vp)
// vx and vy both represent interface values.
vx, vy := vs.Field(0), vs.Field(1)
fmt.Println(vx.CanSet(), vx.CanAddr()) // true true
// vy is addressable but not modifiable.
fmt.Println(vy.CanSet(), vy.CanAddr()) // false true
vb := reflect.ValueOf(123)
vx.Set(vb) // okay, for vx is modifiable
// vy.Set(vb) // will panic, for vy is unmodifiable
fmt.Println(s) // {123 <nil>}
fmt.Println(vx.IsNil(), vy.IsNil()) // false true
}
对于方法类型的 value,我们也可以直接进行调用
package main
import "fmt"
import "reflect"
type T struct {
A, b int
}
func (t T) AddSubThenScale(n int) (int, int) {
return n * (t.A + t.b), n * (t.A - t.b)
}
func main() {
t := T{5, 2}
vt := reflect.ValueOf(t)
vm := vt.MethodByName("AddSubThenScale")
results := vm.Call([]reflect.Value{reflect.ValueOf(3)})
fmt.Println(results[0].Int(), results[1].Int()) // 21 9
neg := func(x int) int {
return -x
}
vf := reflect.ValueOf(neg)
fmt.Println(vf.Call(results[:1])[0].Int()) // -21
fmt.Println(vf.Call([]reflect.Value{
vt.FieldByName("A"), // panic on changing to "b"
})[0].Int()) // -5
}