Package reflect
实现了运行时反射,允许程序获取任意对象的运行时信息。最常见的用法就是通过调用TypeOf
方法获取对象类型;调用ValueOf
返回对象运行时数据。反射是程序检查自身结构的一种能力,是一种形式的元编程。
类型和接口(Types and interfaces)
反射构建在类型系统之上。Go
是静态类型语言,每个变量都有一个静态类型,在编译阶段确认。
1 | type MyInt int |
变量i
的类型为int
,j
的类型为MyInt
,虽然i
和j
的底层类型都是int
类型,但它们之间如果不进行类型转换则不能进行赋值。interface{}
可以表示任何类型的数据。
Go反射三大法则
1.从interface{}
开始进行对象的反射
简单来说反射就是一种从`interface`类型的变量取出里面的`Type`和`value`的一种机制。通过`reflect.TypeOf`和`reflect.ValueOf` 可以分别获取反射的类型和值。
1 | func main() { |
上述代码表明变量x
的类型为float64
,而且传递给函数TypeOf
的参数x
是float64
类型,而不是interface
类型,所以这跟interface
又有什么关系呢?
查看函数TypeOf
源码1
2
3
4
5
6// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ)
}
发现TypeOf
的参数类型为interface{}
,所以参数x
会存储在一个空的interface
中,然后再从这个interface
中恢复类型信息。func ValueOf(i interface{}) Value
也是如此。
2.从反射对象可以获得interface
的值
对于一个reflect.Value
类型的对象(反射对象),我们可以通过Interfaace
方法从中获取interface
值。1
2
3
4
5
6func main() {
var x float64 = 3.4
r := reflect.ValueOf(x)
fmt.Println(r.Interface())
// output: 3.4
}
1 | func (v Value) Interface() (i interface{}) { |
reflect.ValueOf
的作用是把float64
类型的变量转换成reflect.Value
类型,而Interface
的作用与reflect.ValueOf
正好相反。
3.要想修改一个反射对象,反射对象必须是可设置的
执行如下代码1
2
3
4
5func main() {
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1)
}
所以报错的原因是什么呢?请看如下代码:1
2var x float64 = 3.4
v := reflect.ValueOf(x)
因为Go
语言的函数调用的参数都是值传递的,所以传递给reflect.ValueOf
函数的参数x
并不是x
本身而是x
的一份拷贝。如果v.SetFloat(7.1)
可以设置成功,这并不能更新x
的值,更新的只是x
的拷贝;但是真正的x
并没有更新,这样做不但没有用而且会造成很多的疑惑。
要想对原有变量进行修改可以采用如下方式:1
2
3
4
5
6
7func main() {
i := 3.4
v := reflect.ValueOf(&i) //获取变量指针
v.Elem().SetFloat(10) //通过Elem()获取指针指向的变量,SetFloat对变量进行更新
fmt.Println(i)
//output :10
}
通过反射对结构体进行修改:1
2
3
4
5
6
7
8func main() {
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
s.Field(0).SetInt(10)
fmt.Println(s.Field(0))
// output: 10
}
Ref:
1.https://golang.org/pkg/reflect/
2.https://blog.golang.org/laws-of-reflection