Go 言語にはリフレクションがあります。 Go 言語は、実行時に変数の値、変数の呼び出しメソッド、および変数によってサポートされる組み込み操作を更新およびチェックするメカニズムを提供しますが、これらの変数の具体的な型はコンパイル時には不明であり、このメカニズムはリフレクションと呼ばれます。 Go 言語のリフレクションは、2 つの重要な型 (Type と Value) を定義するリフレクト パッケージによってサポートされています。リフレクションのインターフェイス値は、reflect.Type とreflect.Value の 2 つの部分で構成されると理解できます。
このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。
Go 言語は、実行時に変数の値、変数のメソッドの呼び出し、および変数によってサポートされる組み込み操作を更新および確認するメカニズムを提供しますが、これらの変数の具体的な型はコンパイル時には不明です。このメカニズムを反射といいます。リフレクションを使用すると、型自体を第一級の値型として扱うこともできます。
Go 言語におけるリフレクション
リフレクションとは、プログラムの実行中にプログラム自体にアクセスして変更する機能を指します。変数がメモリアドレスに変換されるときにコンパイルされ、変数名はコンパイラによって実行可能部分に書き込まれず、プログラムの実行時にプログラム自体の情報を取得できません。
リフレクションをサポートする言語は、プログラムのコンパイル中に、フィールド名、型情報、構造情報などの変数のリフレクション情報を実行可能ファイルに統合し、プログラムにインターフェイスを提供できます。リフレクション情報にアクセスすると、プログラムの実行時に型に関するリフレクション情報を取得し、それらを変更できるようになります。
C/C 言語はリフレクション関数をサポートしておらず、typeid を介して非常に弱いプログラム実行時の型情報しか提供できません。Java や C# などの言語はすべて完全なリフレクション関数をサポートしており、次のような動的言語はLua と JavaScript は、その構文自体により、コードが実行時にプログラム自身の値と型情報にアクセスできるようにするため、リフレクション システムは必要ありません。
Go 言語プログラムのリフレクション システムは、実行可能ファイル空間またはパッケージ内のすべての型情報を取得することはできません。対応する標準ライブラリの字句解析、構文パーサー、および抽象構文ツリー (AST) を使用する必要があります。)ソース コードをスキャンした後にこの情報を取得します。
Go 言語は、プログラムのリフレクション情報にアクセスするためのリフレクト パッケージを提供します。
reflect パッケージ
Go 言語のリフレクションは、reflect パッケージによってサポートされています。このパッケージでは、2 つの重要な型が定義されています: Type と Value 任意のインターフェイス値リフレクションでは、reflect.Type とreflect.Value の 2 つの部分から構成されるものとして理解できます。reflect パッケージは、任意のオブジェクトの Value と Type を取得するための 2 つの関数、reflect.TypeOf とreflect.ValueOf を提供します。
リフレクト型オブジェクト (reflect.Type)
Go 言語プログラムでは、reflect.TypeOf() 関数を使用して値を取得します。型オブジェクト (reflect.Type) を使用すると、プログラムは型オブジェクトを介して任意の値の型情報にアクセスできます。型オブジェクトを取得するプロセスを理解するための例を次に示します:
package main import ( "fmt" "reflect" ) func main() { var a int typeOfA := reflect.TypeOf(a) fmt.Println(typeOfA.Name(), typeOfA.Kind()) }
実行結果は次のとおりです。
コードの説明は次のとおりです:
9 行目は int 型の変数を定義しています。
10行目では、変数aの型オブジェクトtypeOfAをreflect.TypeOf()で取得しており、型はreflect.Type()となっています。
11行目では、typeOfA型オブジェクトのメンバ関数を通じて、typeOfA変数の型名をそれぞれintで取得でき、型(Kind)はintとなっています。
リフレクションのタイプと種類
リフレクションを使用する場合、まずタイプを理解する必要があります。タイプ)と種類(Kind)。プログラミングでは、最も一般的に使用される型は type ですが、リフレクションでは、多種多様な型を区別する必要がある場合、kind (Kind) が使用されます。例えば、型内のポインタを一律に判定する必要がある場合には、種類(Kind)情報を使用すると便利です。
1) リフレクション型 (種類) の定義
Go 言語プログラムの型 (Type) は、int、string、などのシステムのネイティブ データ型を指します。 bool 、 float32 などの型、および type キーワードを使用して定義された型の場合、これらの型の名前は型自体の名前です。たとえば、タイプ A struct{} を使用して構造体を定義する場合、A は struct{} のタイプになります。
Kind はオブジェクトのタイプを指します。これは、reflect パッケージで次のように定義されます。
type Kind uint const ( Invalid Kind = iota // 非法类型 Bool // 布尔型 Int // 有符号整型 Int8 // 有符号8位整型 Int16 // 有符号16位整型 Int32 // 有符号32位整型 Int64 // 有符号64位整型 Uint // 无符号整型 Uint8 // 无符号8位整型 Uint16 // 无符号16位整型 Uint32 // 无符号32位整型 Uint64 // 无符号64位整型 Uintptr // 指针 Float32 // 单精度浮点数 Float64 // 双精度浮点数 Complex64 // 64位复数类型 Complex128 // 128位复数类型 Array // 数组 Chan // 通道 Func // 函数 Interface // 接口 Map // 映射 Ptr // 指针 Slice // 切片 String // 字符串 Struct // 结构体 UnsafePointer // 底层指针 )
Map、Slice、および Chan は参照タイプであり、使用されるポインターに似ていますが、型定数定義はまだ独立した型に属しており、Ptr には属していません。型 A struct{} で定義された構造体は Struct 型に属し、*A は Ptr に属します。
2) 型オブジェクトから型名と型を取得する
Go言語における型名に対応するリフレクション取得メソッドは、 Reflect.Type は、型名を表す文字列を返します。type 属性 (Kind) は、reflect.Type の Kind() メソッドを使用し、reflect.Kind 型の定数を返します。
下面的代码中会对常量和结构体进行类型信息获取。
package main import ( "fmt" "reflect" ) // 定义一个Enum类型 type Enum int const ( Zero Enum = 0 ) func main() { // 声明一个空结构体 type cat struct { } // 获取结构体实例的反射类型对象 typeOfCat := reflect.TypeOf(cat{}) // 显示反射类型对象的名称和种类 fmt.Println(typeOfCat.Name(), typeOfCat.Kind()) // 获取Zero常量的反射类型对象 typeOfA := reflect.TypeOf(Zero) // 显示反射类型对象的名称和种类 fmt.Println(typeOfA.Name(), typeOfA.Kind()) }
运行结果如下:
代码说明如下:
第 17 行,声明结构体类型 cat。
第 20 行,将 cat 实例化,并且使用 reflect.TypeOf() 获取被实例化后的 cat 的反射类型对象。
第 22 行,输出 cat 的类型名称和种类,类型名称就是 cat,而 cat 属于一种结构体种类,因此种类为 struct。
第 24 行,Zero 是一个 Enum 类型的常量。这个 Enum 类型在第 9 行声明,第 12 行声明了常量。如没有常量也不能创建实例,通过 reflect.TypeOf() 直接获取反射类型对象。
第 26 行,输出 Zero 对应的类型对象的类型名和种类。
指针与指针指向的元素
Go语言程序中对指针获取反射对象时,可以通过 reflect.Elem() 方法获取这个指针指向的元素类型,这个获取过程被称为取元素,等效于对指针类型变量做了一个*操作,代码如下:
package main import ( "fmt" "reflect" ) func main() { // 声明一个空结构体 type cat struct { } // 创建cat的实例 ins := &cat{} // 获取结构体实例的反射类型对象 typeOfCat := reflect.TypeOf(ins) // 显示反射类型对象的名称和种类 fmt.Printf("name:'%v' kind:'%v'\n", typeOfCat.Name(), typeOfCat.Kind()) // 取类型的元素 typeOfCat = typeOfCat.Elem() // 显示反射类型对象的名称和种类 fmt.Printf("element name: '%v', element kind: '%v'\n", typeOfCat.Name(), typeOfCat.Kind()) }
运行结果如下:
代码说明如下:
第 13 行,创建了 cat 结构体的实例,ins 是一个 *cat 类型的指针变量。
第 15 行,对指针变量获取反射类型信息。
第 17 行,输出指针变量的类型名称和种类。Go语言的反射中对所有指针变量的种类都是 Ptr,但需要注意的是,指针变量的类型名称是空,不是 *cat。
第 19 行,取指针类型的元素类型,也就是 cat 类型。这个操作不可逆,不可以通过一个非指针类型获取它的指针类型。
第 21 行,输出指针变量指向元素的类型名称和种类,得到了 cat 的类型名称(cat)和种类(struct)。
【相关推荐:Go视频教程】
以上がGo 言語にはリフレクションがありますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。