875 字
4 分钟
Go 语言学习笔记 -第12章

Go 语言学习笔记 -第12章#

反射#

基本介绍#

1、反射运行在运行时动态 获取变量的各种信息,包括变量的类型、类别

2、如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段,方法)

3、通过反射,可以修改变量的值,可以调用关联的方法

4、使用反射,需要import reflect

应用场景#

1、不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口 这种需要对函数或者方法反射,比如

func bridge(funcPtr interface{}, args....interface{})
第一个参数funcPtr以接口的形式传入函数指针,
函数参数args以可变参数的形式传入
bridge函数中可以用反射来动态执行funcPtr函数

2、结构体序列化 ,如果结构体有指定tag, 也可以使用反射生成对应的字符串

type Monster struct {
Name string `json:"name"`
Age int `json:"age"`
}

3、重要函数

reflect.TypeOf - 获取变量的类型
reflect.ValueOf - 获取变量的值

例子:

package main
import (
"fmt"
"reflect"
)
func reflectTest01(b interface{}) {
//通过反射获取变量的type, kind,value
//1.获取reflect.Type
rType := reflect.TypeOf(b)
fmt.Println("rType=", rType) //int
//2.获取reflect.Value
rVal := reflect.ValueOf(b)
// n1 := 10
// n2 := 2 + n1
// n2 := 2 + rVal //invalid operation: 2 + rVal (mismatched types int and reflect.Value)
n2 := 2 + rVal.Int()
fmt.Println("rVal=", rVal) //100
fmt.Println("n2=", n2) //102
fmt.Printf("rVal=%v, rval type=%T\n", rVal, rVal) //rVal=100, rval type=reflect.Value
//将rval转成interface{}
iV := rVal.Interface()
//通过断言转成需要的类型
num2 := iV.(int)
fmt.Println("num2=", num2)
}
type Student struct {
Name string
Age int
}
type Monster struct {
Name string
Age int
}
func main() {
stu := Student{
Name: "tom",
Age: 20,
}
reflectTest01(stu)
}
package main
import (
"fmt"
"reflect"
)
func reflectTest02(b interface{}) {
//通过反射获取变量的type, kind,value
//1.获取reflect.Type
rType := reflect.TypeOf(b)
fmt.Println("rType=", rType) //rType= main.Student
//2.获取reflect.Value
rVal := reflect.ValueOf(b)
//将rval转成interface{}
iV := rVal.Interface()
fmt.Printf("iV=%v, iV=%T\n", iV, iV) //iV={tom 20}, iV=main.Student
// fmt.Printf("name=%v", iV.Name) //iV.Name undefined (type interface {} is interface with no methods)
//通过断言转成需要的类型
stu, ok := iV.(Student)
if ok {
fmt.Printf("stu.Name=%v", stu.Name)
}
}
type Student struct {
Name string
Age int
}
type Monster struct {
Name string
Age int
}
func main() {
stu := Student{
Name: "tom",
Age: 20,
}
reflectTest02(stu)
}

反射细节:

1、reflect.Value.Kind 获取变量的类别

//1.获取reflect.Type
rType := reflect.TypeOf(b)
fmt.Println("rType=", rType) //rType= main.Student
//2.获取reflect.Value
rVal := reflect.ValueOf(b)
//3.获取reflect.kind
// rKind := rVal.Kind()
rKind := rType.Kind()
fmt.Println("rKind=", rKind)

2、Type是类型,Kind是类别 Type和Kind可能是相同的,也可能是不同的

如:

var num int = 10 num 的Type 是int, Kind也是int
var stu Student stu的Type是包名.Student, Kind是struct

3、通过反射可以让变量在interface{} 和reflect.value之间相互转换

4、使用反射的方式来获取变量的值 要求数据类型匹配

如果x是int,那么就应该使用reflect.Value(x).Int(),而不能使用其他的

5、通过反射来修改变量,当使用SetXX方法来设置需要通过对应的指针类型 来完成,这样才能改变传入的变量的值,同时需要使用reflect.Value.Elem方法

6.reflect.Value.Elem()怎么理解:

package main
import (
"fmt"
"reflect"
)
func reflectTest(b interface{}) {
//获取reflect.Value
rVal := reflect.ValueOf(b)
rKind := rVal.Kind()
fmt.Printf("rval kind=%v\n", rKind) //ptr
//改变值
rVal.Elem().SetInt(20) //这里elem很重要
//可以这样理解Val.Elem()
// num := 9
// ptr *int = &num
// num2 := *ptr
}
type Student struct {
Name string
Age int
}
type Monster struct {
Name string
Age int
}
func main() {
var num int = 10
reflectTest(&num)
// reflectTest(num)
fmt.Println("num=", num)
}
Go 语言学习笔记 -第12章
https://blog.zhequtao.com/posts/golang/go-learning/学习笔记-go/第12章/
作者
阿俊
发布于
2020-03-30
许可协议
CC BY-NC-SA 4.0

相关阅读