反射 (relect包)
反射 (relect包)
核心:relect包
概念
Go反射可以做什么?
- 运行时动态获取:变量的各种信息 
- 普通变量的 类型、类别等
 - 结构体的 字段、方法
 
 - 运行时动态修改和调用 
- 修改变量的值
 - 调用关联的方法
 
 
相关函数
// `reflect包.TypeOf(变量名)`,获取变量的类型,返回reflect.Type类型
func TypeOf(i interface{}) Type
// `reflectb包.ValueOf(变量名)`,获取变量的值,返回reflect.Value类型。通过该类型可以获取该变量很多信息
func ValueOf(i interface{}) Value两个主要方法和类型
TypeOf
见下,代码连在一起了
ValueOf
package main
import(
	"fmt"
    "reflect"
)
func testReflect(i interface{})	{ 		// 100 (`int` -> `interface{}`, 空接口)
    // TypeOf
    reType := reflect.TypeOf(i)
    fmt.Println("reType:", reType)		// int
    
    // ValueOf
    reValue2 := reflect.ValueOf(i)		// 100 (`interface{}` -> `reflect.Value`)
    fmt.Println("reValue:", reValue2)
}
type Student struct{
    Name string
    Age int
}
func main() {
    // 基本类型
	var num int = 100
    testReflect(num)
    
    // 结构体类型
    student := Student {
        Name: "Lili",
        Age: 18,
    }
    testReflect(student)
}reflect.Type
获取变量的类别
获取变量类别有两种方式:
k1 := reType.Kind()
fmt.Println(k1)		// struct
k2 := reValue.Kind()
fmt.Println(k2)		// struct注意区分:类别 与 类型
Kind方法只能获取到是struct (类别),并无法获取到类名 (类型)
reflect.Value
类型互转
基本类型
基本、interface{}、reflect.Value 三者互转
num1 := 100
var inter1 interface{} = num1		// 100 (`int` 			-> `interface{}`)
num2, _ := inter2.(int)				// 100 (`interface{}`	-> `int`) 类型断言
reValue2 := reflect.ValueOf(num1)	// 100 (`int`			-> `reflect.Value`)
reValue := reflect.ValueOf(inter1)	// 100 (`interface{}`	-> `reflect.Value`)
num3 := reValue.Int()				// 100 (`reflect.Value`	-> `int`)
inter2 := reValue.Interface() 		// 100 (`reflect.Value`	-> `interface{}`)结构体
结构体、interface{}、reflect.Value 三者互转
student := Student {
    Name: "Lili",
    Age: 18,
}
var inter1 interface{} = stu1		// Lili 18 (`XStruct` 		-> `interface{}`)
stu2, flag := inter2.(Student)		// Lili 18 (`interface{}`	-> `XStruct`) 类型断言,需要判断flag
reValue2 := reflect.ValueOf(stu1)	// Lili 18 (`XStruct`		-> `reflect.Value`)
reValue := reflect.ValueOf(inter1)	// Lili 18 (`interface{}`	-> `reflect.Value`)
stu3, _ := rV.Interface().(Student)	// Lili 18 (`reflect.Value`	-> `XStruct`) 这里无法直接转换,需要先转空接口再用类型断言
inter2 := reValue.Interface() 		// Lili 18 (`reflect.Value`	-> `interface{}`)修改变量的值
基本类型 (.Elem、.setInt)
需要用到一个接口
// 原型
// @param v Elem方法会返回v保管值的Value封装,或v持有指针指向值的Value封装。如果v的Kind不是Interface或Ptr会Panic
// @return 如果v持有值为nil,会返回Value零值
func (v Value) Elem() Value首先这里修改成传递地址
// 变量准备
var i1 = 100
var inter1 interface{} = &i1
// 修改值
reValue := reflect.ValueOf(inter1)		// 对应 `*int`
reValue2 := reValue.Elem()				// 对应 `int引用`
reValue2.SetInt(40)						// 修改值
fmt.println(i1)							// 40结构体 (多了个Field()方法)
// 变量准备
type Student struct{
    Name string
    Age int
}
s := Student{
    Name: "Lili"
    Age: 18
}
var inter1 interface{} = &s
// 修改值
reValue := reflect.ValueOf(inter1)		// 对应 `*Student`
reValue2 := reValue.Elem()				// 对应 `Student引用`
//n := reValue2.NumField()				// 字段数。2
reValue2.Field(0).SetString("LiSi")		// 修改值操作结构体的字段和方法
package main
import(
	"fmt"
    "reflect"
)
// 类
type Student struct{
    Name string
    Age int
}
func (s Student) CPrint() {
    fmt.Println("调用了Print方法")
    fmt.Println("学生名:", s.Name)
}
func (s Student) AGetSum(n1, n2 int) int {
    return n1+n2
}
func (s Student) BSet(name string, age int) int {
	s.Name = name
    s.Age = age
}
// 操作结构体进行反射
func TestStudentStruct(a interface{}){
    reV := reflect.ValueOf(a)			// `interface{}` -> `reflect.Value`
    
    // 结构体字段
    n1 := reV.NumField()				// 获取结构体字段数量。打印:2
    for i:=0; i<n1; i++{				// 获取结构体字段内容
        fmt.Printf("第%d个字段的值为:%v\n", i, val.Field(i))
    }
    
    // 结构体方法
    n2 := reV.NumMethod()				// 获取结构体方法数量。打印:3
    vaV.Method(2).Call(nil)				// 调用结构体方法。 (需要注意,这玩意居然是按字母而非定义顺序排序的。这里调用的是CPrint方法)
}
// 主函数
func main() {
    s := Student{
        Name: "Lili"
        Age: 18
    }
    TestStudentStruct(s)
}链接到当前文件 0
没有文件链接到当前文件