- 定律一:反射可以将“接口类型变量”转换为“反射类型对象”
func TypeOf(i interface{
}) Type
func ValueOf(i interface{
}) Value
执行函数 reflect.TypeOf ()和 reflect.ValueOf()的入参都是作为一个接口传入,返回反射类型的对象。
- 定律二:反射可以将“反射类型对象”转换为“接口类型变量”
func (v Value) Interface() (i interface{
})
package main
import ("fmt""reflect"
)
func main() {
var a int = 30v := reflect.ValueOf(a) //返回Value类型对象fmt.Println(v)v1 := v.Interface() //返回空接口变量v2 := v1.(int) //类型断言,断定v1中type=intfmt.Printf("%T %v\n", v2, v2)fmt.Println(v2)
}
- 定律三:如果要修改“反射类型对象”,其值必须是“可写的”(settable)
案例一:
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("v:", v.CanSet())//判断可写性 false
v.SetFloat(7.1) //panic.
x到v是一个值拷贝,如果v.SetFloat(7.1)
这行代码能够成功执行,它不会更新 x ,虽然看起来变量 v 是根据 x 创建的。相反,它会更新 x 存在于 反射对象 v 内部的一个拷贝,而变量 x 本身完全不受影响。这会造成迷惑,并且没有任何意义,所以是不合法的。“可写性”就是为了避免这个问题而设计的。
案例二:
既然是值拷贝,那我们传递地址会怎么样?
var x float64 = 3.4
p := reflect.ValueOf(&x) // &x.
fmt.Println("type of p:", p.Type())//*float64
fmt.Println("settability of p:", p.CanSet())//false
v.SetFloat(7.1) //panic.
同样不能做修改,这是因为v当前保存的是x的地址,而不是x的原始空间。
fmt.Println(p) //0xc420014060
因此我们可以可以调用 Value 类型的 Elem 方法。Elem 方法能够对指针进行“解引用”。
package mainimport ("fmt""reflect"
)func main(){
var x float64 = 3.4p := reflect.ValueOf(&x)fmt.Println(p)//0xc420014060fmt.Println("p:", p.CanSet())//falsev:=p.Elem()//Elem()对指针解引用fmt.Println("v:", v.CanSet())//truev.SetFloat(6.6)fmt.Println(v)//6.6
}