この記事の一部は機械翻訳を使ってるよ
Golang シリーズ
Hello GoLang: https://blog.yexca.net/ja/archives/154
GoLang (var and const) 変数と定数: https://blog.yexca.net/ja/archives/155
GoLang (func) 関数: https://blog.yexca.net/ja/archives/156
GoLang (slice and map) スライス: https://blog.yexca.net/ja/archives/160
GoLang (OOP) オブジェクト指向: https://blog.yexca.net/ja/archives/162
GoLang (reflect) リフレクション: この記事
GoLang (struct tag) 構造タグ: https://blog.yexca.net/ja/archives/205
GoLang (goroutine) ゴルーチン: https://blog.yexca.net/ja/archives/206
GoLang (channel) チャンネル: https://blog.yexca.net/ja/archives/207
反射指の一種の用途であり、自己記述と自己制御が可能です
pair
Go 言語变量には type と value の部分が含まれ、pair で構成されます
static type はコード実行時に見られるタイプであり、concrete type は runtime システムに見られるタイプです。
このタイプは、static type ではなく変数の concrete type に応じて成功するかどうかを判断します。したがって、concrete type が write メソッドの命令も実装している場合、タイプは write として承認される可能性があります。
反射はタイプに基づいて確立され、静的タイプであり、固定されているため、反射は主に interface タイプに関係します (concrete type)
package main
import "fmt"
type ReadBook interface {
Read()
}
type WriteBook interface {
Write()
}
type Book struct {
}
func (this *Book) Read() {
fmt.Println("read Book")
}
func (this *Book) Write() {
fmt.Println("write Book")
}
func main() {
// b: pair<type:Book, value:book{} のアドレス>
b := &Book{}
// r: pair<type:, value:>
var r ReadBook
// r: pair<type:Book, value:book{} のアドレス>
r = b
r.Read()
var w WriteBook
w = r.(WriteBook) // r のタイプは Book であるため
w.Write()
}
TypeOf と ValueOf
Reflect.TypeOf() は pair 中の type を取得します、reflect.ValueOf() は pair 中の value を取得します
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a)) // float64
fmt.Println("value of a:", reflect.ValueOf(a)) // 3.14
}
型转换
reflect.ValueOf() を実行すると、型が reflect.Value 变量になります。
既知原データの種類
既知原データ型は直接强制转换可能
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a))
fmt.Println("value of a:", reflect.ValueOf(a))
value := reflect.ValueOf(a)
fmt.Printf("type of value:%T\n", value) // reflect.Value
newA := value.Interface().(float64)
fmt.Printf("type of newA:%T\n", newA) // float64
}
型変換は完全に一貫している必要があることに注意することが重要です。そうでないと、ポインタなどの panic が発生します。
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a))
fmt.Println("value of a:", reflect.ValueOf(a))
// 輸送先住所
point := reflect.ValueOf(&a)
fmt.Printf("type of value:%T\n", point) // reflect.Value
// 型をポインタに変換する
newA := point.Interface().(*float64)
fmt.Printf("type of newA:%T\n", newA) // *float64
}
つまり、反射することができます “反射型オブジェクト” 再再再转换は “インターフェース変数”
未知原データ型
Field を横断して取得
package main
import (
"fmt"
"reflect"
)
type Person struct {
// 一行は 1 つの field です
Name string
Age int
Rank float64
}
// メソッドはパブリックであることに注意してください。プライベートの場合はアクセスできません。
func (person Person) Sleep() {
fmt.Println("person sleep")
}
func main() {
p := Person{"zhangSan", 18, 5.2}
getFieldAndMethod(p)
}
func getFieldAndMethod(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("type:", getType.Name())
getValue := reflect.ValueOf(input)
fmt.Println("value/AllField:", getValue)
// 属性を取得します
numField := getValue.NumField()
for i := 0; i < numField; i++ {
fieldType := getType.Field(i)
fieldValue := getValue.Field(i).Interface()
fmt.Printf("%s: %v = %v\n", fieldType.Name, fieldType.Type, fieldValue)
}
// メソッドを取得します
numMethod := getType.NumMethod()
for i := 0; i < numMethod; i++ {
method := getType.Method(i)
fmt.Printf("%s: %v\n", method.Name, method.Type)
}
}
reflect.Value による割り当て
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
// ポインタの場合のみ割り当て可能
pointer := reflect.ValueOf(&a)
// 元の値を取得するためのアドレスを設定します
newValue := pointer.Elem()
// 値が設定可能かどうかをチェックする
fmt.Println("value canSet:", newValue.CanSet())
if newValue.CanSet() {
// 設定できる場合
newValue.SetFloat(9.96)
// 変数の値を表示
fmt.Println("value of a:", a) // 9.96
} else {
fmt.Println("error")
}
}
reflect.Value 経由でメソッドを呼び出す
関数名による呼び出し
package main
import (
"fmt"
"reflect"
)
type User struct {
name string
age int
}
func (user User) MethodHasArgs(a string, b int) {
fmt.Println("User MethodHasArgs")
}
func (user User) MethonNotArgs() {
fmt.Println("User MethodNotArgs")
}
func main() {
user := User{"zhangSan", 18}
value := reflect.ValueOf(user)
// 関数名で呼び出す
method1 := value.MethodByName("MethodHasArgs")
// ビルドパラメータ
args1 := []reflect.Value{reflect.ValueOf("string"), reflect.ValueOf(18)}
// 関数の呼び出し
method1.Call(args1)
// パラメータなしで呼び出す
method2 := value.MethodByName("MethonNotArgs")
args2 := make([]reflect.Value, 0)
method2.Call(args2)
}