記事のディレクトリ
反射
- 基本的な紹介
- リフレクションは、変数のタイプ(タイプ)、カテゴリ(種類)など、実行時に変数に関するさまざまな情報を動的に取得できます。
- 構造体変数の場合は、構造体自体の情報(構造体のフィールドとメソッドを含む)も取得できます。
- リフレクションを通じて、変数の値を変更し、関連するメソッドを呼び出すことができます。
- リフレクションを使用するには、インポート(「リフレクト」)が必要です
- アプリケーションシナリオ
- インターフェイスがどの関数を呼び出すのかわからず、受信パラメータに基づいて実行時に呼び出される特定のインターフェイスを決定します。これは、関数またはメソッドに反映する必要があります。
- 構造をシリアル化するときに、構造に指定されたタグがある場合、リフレクションは対応する文字列を生成するためにも使用されます。
- 共通の機能と概念
- Reflect.TypeOf(変数名)、変数のタイプを取得し、reflect.Typeタイプを返します
//使用 reflect.TypeOf() 函数可以获得任意值的类型对象,通过类型对象可以访问任意值的类型信息。
rTyp := reflect.TypeOf(b)
fmt.Println("rType=", rTyp)
-
Reflect.ValueOf(変数名)、変数の値を取得し、reflectを返します。
値型reflect.Valueは-構造型です。Reflect.Valueを使用すると、変数に関する多くの情報を取得できます。
//使用 reflect.TypeOf() 函数可以获得任意值的类型对象,通过类型对象可以访问任意值的类型信息。
rTyp := reflect.TypeOf(b)
fmt.Println("rType=", rTyp)
- 変数interface()とreflect.Valueは相互に変換できます。
var num int = 100
rVal := reflect.ValueOf(b)
//下面我们将 rVal 转成 interface{}
iV := rVal.Interface()
//将 interface{} 通过断言转成需要的类型
num2 := iV.(int)
fmt.Println("num2=", num2)
- Reflect.TypeOf.Elem()ポインタ型の要素型を取得します
type Student struct {
Name string `json:"username"`
Age int
}
func main() {
stu := Student{
Name : "tom",
Age : 20,
}
rTyp := reflect.TypeOf(stu)
// 获取指针类型的元素类型
e := rTyp.Elem()
// 显示指针变量指向元素的类型名称和种类
fmt.Printf("name:'%v' kind:'%v'\n", e.Name(), e.Kind()) // name:'User' kind:'struct'
}
- 任意の値のリフレクションオブジェクト情報がreflect.TypeOf()を介して取得された後、そのタイプが構造体である場合、構造体メンバーの詳細情報は、リフレクション値オブジェクトのNumField()およびField()メソッドを介して取得できます( Reflect.Type)。
type User struct {
Name string `json:"username"`
Age int
Salary float64
}
func main() {
user := User{"pd", 18, 9999.99}
tf := reflect.TypeOf(user)
// 遍历结构体所有成员
for i := 0; i < tf.NumField(); i++ {
// 获取每个成员的结构体字段类型
fieldType := tf.Field(i)
fmt.Printf("name:'%v' tag:'%v'\n", fieldType.Name, fieldType.Tag)
// name:'Name' tag:'json:"username"'
// name:'Age' tag:''
// name:'Salary' tag:''
}
// 通过字段名, 找到字段类型信息
userType, ok := tf.FieldByName("Name")
if ok {
// 从tag中取出需要的tag
fmt.Println(userType.Tag.Get("json")) // username
}
}
- リフレクションを通じて価値情報を得る
func main() {
// 声明整型变量a并赋初值
var a int
a = 666
// 获取变量a的反射值对象
vf := reflect.ValueOf(a)
// 将vf反射值对象以Interface{}类型取出, 通过类型断言转换为int类型
r1 := vf.Interface().(int)
// 将vf反射值对象以int64类型取出
r2 := vf.Int()
// 强制类型转换为int类型
r3 := int(r2)
fmt.Printf("r1值:%v r1类型:%T\n", r1, r1) // r1值:666 r1类型:int
fmt.Printf("r2值:%v r2类型:%T\n", r2, r2) // r2值:666 r2类型:int64
fmt.Printf("r3值:%v r3类型:%T\n", r3, r3) // r3值:666 r3类型:int
}
- リフレクションを介して構造メンバーの値にアクセスします
type User struct {
Name string
Age int
Salary float64
}
func main() {
user := User{"pd", 18, 9999.99}
vf := reflect.ValueOf(user)
// 获取字段数量
fmt.Printf("NumField:%v\n", vf.NumField()) // NumField:3
// 获取索引为2的字段
field := vf.Field(2)
fmt.Println(field.Type()) // float64
// 根据名字查找字段
fbn := vf.FieldByName("Name")
fmt.Println(fbn.Type()) // string
// 根据索引查找字段
fbi := vf.FieldByIndex([]int{1})
fmt.Println(fbi.Type()) // int
}
- 反射値のヌルと妥当性を判断します
func main() {
// *int的空指针
var a *int
fmt.Println(reflect.ValueOf(a).IsNil()) // true
// nil值
fmt.Println(reflect.ValueOf(nil).IsValid()) // false
// 实例化一个结构体
s := struct{}{}
// 尝试从结构体中查找一个不存在的字段
fmt.Println(reflect.ValueOf(s).FieldByName("").IsValid()) // false
// 尝试从结构体中查找一个不存在的方法
fmt.Println(reflect.ValueOf(s).MethodByName("").IsValid()) // false
}
- リフレクションを使用して変数を変更します。SetXxxメソッドを使用して設定する場合は、対応するポインタータイプを使用して行う必要があるため、入力変数の値を変更できます。また、reflect.Value.Elem()メソッドは次のことを行う必要があります。利用される。
var num int = 10
//2. 获取到 reflect.Value
rVal := reflect.ValueOf(num)
//3. Elem返回v持有的接口保管的值的Value封装,或者v持有的指针指向的值的Value封装
rVal.Elem().SetInt(20)
fmt.Println("num=", num) // 20
- タイプ情報を使用してインスタンスを作成します
func main() {
var a int
// 取变量a的反射类型对象
tf := reflect.TypeOf(a)
// 根据反射类型对象创建这个类型的实例值,值以 reflect.Value 类型返回
obj := reflect.New(tf)
// 输出类型和种类
fmt.Printf("type:%v kind:%v\n", obj.Type(), obj.Kind()) // type:*int kind:ptr
}
- リフレクションによる関数とメソッドの呼び出し
// add函数
func add(a, b int) int {
return a + b
}
func main() {
// 将函数包装为反射值对象
vf := reflect.ValueOf(add)
// 构造函数参数, 传入两个整型值
paramList := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)}
// 反射调用函数
retList := vf.Call(paramList)
// 获取第一个返回值, 取整数值
fmt.Println(retList[0].Int()) // 30
}
- 予防
-
Reflect.Value.Kind、変数のカテゴリを取得し、定数を返します
-
タイプと種類の違い
タイプはタイプ、種類はカテゴリ、タイプと種類は同じでも異なっていてもかまいません。
rTyp := reflect.TypeOf(b)
rVal := reflect.ValueOf(b)
//(1) rVal.Kind() ==>
kind1 := rVal.Kind()
//(2) rTyp.Kind() ==>
kind2 := rTyp.Kind()
- リフレクションを通じて、変数はinterface()とReflect.Valueの間で変換できます。
- リフレクションを使用してトラフィックの値を取得し(そして対応するタイプを返し)、データタイプが一致する必要があります
var num int = 100
rTyp := reflect.TypeOf(num)
rVal := reflect.ValueOf(num)
n2 := 2 + rVal.Int()
//n3 := rVal.Float() //error panic
- リフレクションを使用して変数を変更します。SetXxxメソッドを使用して設定する場合は、対応するポインタータイプを使用して行う必要があるため、入力変数の値を変更できます。また、reflect.Value.Elem()メソッドは次のことを行う必要があります。利用される。
var num int = 10
//2. 获取到 reflect.Value
rVal := reflect.ValueOf(num)
//3. Elem返回v持有的接口保管的值的Value封装,或者v持有的指针指向的值的Value封装
rVal.Elem().SetInt(20)
fmt.Println("num=", num) // 20
- Reflect.Value.Elem()は、変数へのポインターを取得するために使用されます
type User struct {
Name string
Age int
Salary float64
}
func main() {
// 声明一个空结构体
type User struct {}
// 创建User的实例
user := &User{}
// 获取结构体实例的反射类型对象
t := reflect.TypeOf(user)
// 显示反射类型对象的名称和种类
fmt.Printf("name:'%v' kind:'%v'\n", t.Name(), t.Kind()) // name:'' kind:'ptr'
// 获取指针类型的元素类型
e := t.Elem()
// 显示指针变量指向元素的类型名称和种类
fmt.Printf("name:'%v' kind:'%v'\n", e.Name(), e.Kind()) // name:'User' kind:'struct'
}