最近在看一些go语言标准库以及第三方库的源码时,发现go的reflect被大量使用,虽然反射的机制大多数语言都支持,但好像都没有go一样这么依赖反射的特性。个人觉得,reflect使用如此频繁的一个重要原因离不开go的另一个特性,空接口interface{},reflect配合空接口,让原本是静态类型的go具备了很多动态类型语言的特征。 另外,虽然反射大大增加了go语言的灵活性,但要完全掌握它的原理和使用也还是有一点难度的。
go的reflect库有两个重要的类型:
reflect.Type
reflect.Value
Type,Value分别对应对象的类型和值数据
还有两个重要的函数:
reflect.TypeOf(i interface{}) Type
reflect.TypeOf()返回值的类型就是reflect.Type。
reflect.ValueOf(i interface{}) Value
reflect.ValueIOf()返回值的类型就是reflect.Value
reflect.Type
reflect.TypeOf(i interface{}) Type
因为reflect.Typeof的参数是空接口类型,因此可以接收任意类型的数据。 TypeOf()的返回值是这个接口类型对应的reflect.Type对象。通过Type提供的一些方法,就可以获得这个接口实际的静态类型。
1import (
2 "fmt"
3 "reflect"
4)
5
6type Foo struct {
7 X string
8 Y int
9}
10
11func main() {
12 var i int = 123
13 var f float32 = 1.23
14 var l []string = []string{"a", "b", "c"}
15
16 fmt.Println(reflect.TypeOf(i)) //int
17 fmt.Println(reflect.TypeOf(f)) //float32
18 fmt.Println(reflect.TypeOf(l)) //[]string
19
20 var foo Foo
21 fmt.Println(reflect.TypeOf(foo)) //main.Foo
22
23}
查看reflect包的源代码可以看到,reflect.Type的定义如下:
1type Type interface {
2 Align() int
3 FieldAlign() int
4 Method(int) Method
5 MethodByName(string) (Method, bool)
6 NumMethod() int
7 Name() string
8 String() string
9 Elem() Type
10 Field(i int) StructField
11 FieldByName(name string) (StructField, bool)
12 Len() int
13 .....
14}
15
可见reflect.Type是一个接口类型的对象,这个接口包含了很多方法,像Name(),Field(),Method()等,下面再通过实例来了解几个比较重要的方法。
1type Foo struct {
2 X string
3 Y int
4}
5
6func (f Foo) do() {
7 fmt.Printf("X is: %s, Y is: %d", f.X, f.Y)
8
9}
10
11func main() {
12 var s string = "abc"
13 fmt.Println(reflect.TypeOf(s).String()) //string
14 fmt.Println(reflect.TypeOf(s).Name()) //string
15
16 var f Foo
17 typ := reflect.TypeOf(f)
18 fmt.Println(typ.String()) //main.Foo
19 fmt.Println(typ.Name()) //Foo ,返回结构体的名字
20
21}
上面的例子可见,通过Type.String(),Type.Name()方法就可以获得接口对应的静态类型。 下面几个方法,显示了Type的更多功能,特别是对于结构体对象而言。
阅读(1743) | 评论(0) | 转发(0) |