本学习笔记全部以代码块的形式展示,具体的内容都包含在代码里:
代码语言:javascript复制package types
import (
"fmt"
"reflect"
)
// 1. reflect 是用程序检查其所拥有的结构,尤其是类型的一种能力;这是元编程的一种形式。
// 反射可以在运行时检查类型和变量,例如它的大小、方法,并且能动态的调用其中的方法。
// 2. reflect.TypeOf 和 reflect.ValueOf,返回被检查对象的类型和值。
// 3. 原理上,反射是通过检查一个接口的值,变量首先被转换成空接口。
// 4. 反射可以从接口值反射到对象,也可以从对象反射回接口值。
// 5. reflect.Type 和 reflect.Value 都有许多方法用于检查和操作自身
// 6. 利用reflect 可以更改对象值,反射中有些内容是需要用地址去改变它的状态的。
// 7. reflect 可以反射结构struct。
// 定义 NotKnownType
type NotKnownType struct {
a, b, c string
}
// 定义方法
func (n NotKnownType) GetStr() string {
return n.a n.b n.c
}
func (n NotKnownType) GetStr1(str string) string {
return n.a n.b n.c str
}
// 定义 NotKnownType
type NotKnownType1 struct {
A, B, C string
}
func ReflectExample() {
var x int8 = 10
// t 是 reflect.Type 类型
t := reflect.TypeOf(x)
// v 是 reflect.Value 类型
v := reflect.ValueOf(x)
fmt.Println("t: ", t)
fmt.Println("v: ", v)
// 5
fmt.Println("reflect.Value.Type: ", v.Type())
// Kind 方法总是返回底层类型
fmt.Println("reflect.Type.Kind, reflect.Value.Kind: ", t.Kind(), v.Kind(), t.Kind() == reflect.Int8)
fmt.Println("reflect.Value.Int: ", v.Int())
// 6
// 使用 CanSet 判断是否可以更改值
fmt.Println("reflect.Value.CanSet: ", v.CanSet())
// 上述得到的是 false,因为 v 是通过 x 的拷贝创建的,改变 v 并不能改变 x,所以要使用 x的地址
v1 := reflect.ValueOf(&x)
fmt.Println("v1: ", v1, v1.Type())
// 这时还是不能更改值
fmt.Println("reflect.Value.CanSet: ", v1.CanSet())
// 还需要使用 Elem()
v1 = v1.Elem()
fmt.Println("reflect.Value.CanSet: ", v1.CanSet())
// 更改值
v1.SetInt(20)
fmt.Println("reflect.Value.SetInt: ", v1, x)
// 7
// 假设不知道 n 具体的struct类型
var n interface{} = NotKnownType{"a", "b", "c"}
t2 := reflect.TypeOf(n)
v2 := reflect.ValueOf(n)
fmt.Println("t2: ", t2)
fmt.Println("v3: ", v2)
// 可使用 NumField 返回结构体的字段数量,使用 Field 得到该字段的值
for i := 0; i < v2.NumField(); i {
fmt.Printf("reflect.Value.Field %d: %vn", i, v2.Field(i))
}
// 使用 Method(n).Call(nil) 调用结构体中的方法
m1 := v2.Method(0).Call(nil)
param := []reflect.Value{reflect.ValueOf("d")}
m2 := v2.Method(1).Call(param)
fmt.Printf("m1: %v, m2: %vn", m1, m2)
// 当更改struct字段时,字段必须可导出(即首字母要大写),然后结合上述更改的规则
n1 := NotKnownType1{"A", "B", "C"}
v3 := reflect.ValueOf(&n1)
v3 = v3.Elem()
fmt.Println("reflect.Value.CanSet: ", v3.CanSet())
for i := 0; i < v3.NumField(); i {
origin := v3.Field(i)
v3.Field(i).SetString(origin.String() origin.String())
}
fmt.Println("n1: ", n1)
}