本文主要参考 The Laws of Reflection
介绍反射的使用。
类型和接口
golang的类型是静态的,在编译的时候每个变量的类型就确定了,下文以 静态类型
指代。
静态类型包括用户自定义的类型,细分下来,是由基本类型组成的。
接口是静态类型中一种比较重要的类别,是固定数目方法的集合。
空接口 interface{}
更是特别的接口,不要求实现任何方法,任意值都满足,因此可以表示任意值。
接口表示
接口的底层实现可以参考 这篇文章 ,不过可以简单理解为一个 pair
,包括 具体值
和 具体类型信息
。
具体值就是变量的值,具体类型信息可以理解成变量的静态类型(不是对应的接口类型)。
1
2
3
4
5
6
7
8
9
10
11
|
type Stringer interface {
String() string
}
type Intf struct {
Name string
}
func (i Intf) String() string {
return i.Name
}
|
以上面代码为例,Intf类型变量可以赋值给空接口或者Stringer接口类型变量。
不过实际上存储都是具体的Intf变量值以及Intf类型信息。
之所以要存具体类型信息,是因为只知道接口类型的话没法确定对应实现的方法。
接口类型+具体类型才能确定实现接口的具体方法列表(运行时算出并缓存)。
从接口获取反射对象
从接口的表示我们知道,接口包括值和类型,所以反射之后也分为反射类型和反射值。
通过 reflect.TypeOf
我们能获取接口的反射类型。
通过 reflect.ValueOf
我们能获取接口的反射值。
通过 Kind
方法我们能知道存储数据的底层类型/基本类型(Chan, Func, Ptr, Slice…)。
反射值有许多方法可以获取实际的值,如 Float
。
从反射对象获取接口
通过 Interface
方法,我们能从反射值获取接口,为空接口类型。
1
|
func (v Value) Interface() interface{}
|
空接口可以通过类型转换或者switch按类型处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
func ToString(any interface{}) string {
// 类型转换
if v, ok := any.(Stringer); ok {
return v.String()
}
// switch按类型处理
switch v := any.(type) {
case int:
return strconv.Itoa(v)
case bool:
return strconv.FormatBool(v)
}
return "???"
}
|
反射如何修改值
反射值分为只读类型和可设置类型,通过 CanSet
方法可以判断。
类比C语言,我们知道传值与传指针的区别,那就是传指针才能修改实参。
类似的,指针对应的反射值才是可设置的。
变量指针的反射值通过 Elem
方法获取指针指向的、可设置的反射值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var f float64 = 3.4
p := reflect.ValueOf(&f) // f的指针
fmt.Println("type of p:", p.Type())
// 输出 *float64
fmt.Println("settability of p:", p.CanSet())
// 输出 false
v := p.Elem()
fmt.Println("settability of v:", v.CanSet())
// 输出 true
v.SetFloat(7.1)
fmt.Println(f)
// 输出 7.1
|
修改结构体字段值
通过结构体指针的反射值,我们能够获取其指向的实际结构体变量的反射值,进而修改任意字段值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
type T struct {
A int
B string
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
}
s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)
|