背景
和其他语言一样, golang 也提供了反射机制,反射允许我们程序在运行时候动态修改变量调用方法。golang 使用 reflect 包帮我们完成反射工作
解析简单数据类型
关键方法:
-
ValueOf
-
TypeOf
func main() {
var i int = 1
// 解析值
v := reflect.ValueOf(i)
fmt.Println(v.Int())
// 解析类型
t := reflect.TypeOf(i)
fmt.Println(t.Name())
}
解析结构体
关键方法:
-
NumField
-
NumMethod
-
Field
-
Method
type Person struct {
name string
age int
}
func (p *Person) foo() {
// ...
}
func main() {
p := Person{"xiaoming", 12}
// 解析 struct 类型
t := reflect.TypeOf(p)
fmt.Println(t.Name())
// 解析 struct 值
v := reflect.ValueOf(p)
// 输出 struct 中的值
for i := 0; i < t.NumField(); i++ {
tt := t.Field(i)
vv := v.Field(i)
fmt.Println(f.Name, f.Value, vv)
}
// 输出 struct 中的方法
for i := 0; i < t.NumMethod(); i++ {
mm := t.Method(i)
fmt.Println(mm.Name, mm.Type)
}
}
简单修改值
关键方法:
-
Elem
-
SetInt
func main() {
x := 1
v := reflect.ValueOf(&x)
v.Elem().SetInt(2)
// 打印出来就可以发现已经修改了
fmt.Println(x)
}
结构体修改字段
关键方法:
-
Elem
-
FieldByName
-
SetString
修改字段需要也是大驼峰对其他包可见
type Person struct {
name string
age int
}
func main() {
p := Person{"xiaoming", 12}
v := reflect.ValueOf(&p)
// 修改结构体中的变量名
value := v.Elem()
f := value.FieldByName("Name")
f.SetString("XingMing")
}
方法动态调用
关键方法:
-
MethodByName
-
[]reflect.Value{}
-
Call
方法传参时,传入参数需要是 reflect.Value 切片,切片中需要是 reflect.ValueOf 将具体数据进行转换,如下代码,最后通过 Call 来动态调用方法
type Person struct {
name string
age int
}
func (p Pserson) foo(str string) {
fmt.Println("My name is ", str)
}
func main() {
p := Person{"xiaoming", 12}
v := reflect.ValueOf(p)
// 方法
m := v.MethodByName("foo")
// 方法传参
args := []reflect.Value{reflect.ValueOf("huahua")}
// 方法动态调用
m.Call(args)
}