ホームページ  >  記事  >  バックエンド開発  >  Golangのリフレクションの詳しい説明(例)

Golangのリフレクションの詳しい説明(例)

藏色散人
藏色散人転載
2020-09-08 09:21:233941ブラウズ

##golang チュートリアル

Golangのリフレクションの詳しい説明(例)




# 振り返り(例)、困っている友達のお役に立てれば幸いです。 序文

リフレクションは、多くの言語で素晴らしい用途を持っています。コンピューター サイエンスでは、リフレクションとは、自己記述型攻撃と自己制御型攻撃を可能にするアプリケーションのクラスを指します。

この記事は、Golang の考察に関する著者のメモを記録します。

10 秒後には、次の知識ポイントが得られるようになります:

1. リフレクションの概要
2. リフレクションを使用する理由3. リフレクションで正確にできること

テキスト

1. リフレクションの概要Golang は、コンパイル時に が型を認識しないメカニズムを提供します

の場合、

変数を更新

、実行時に値を表示
、メソッドを呼び出し

、その

レイアウトを直接操作できます
このメカニズムはリフレクションと呼ばれます。

2.なぜリフレクションを使用するのでしょうか? たとえば、さまざまなタイプの値を処理できる関数が必要になる場合があります。タイプがわからない場合は、次のように書くかもしれません:
// 伪代码
switch value := value.(type) {
case string:
	// ...一些操作
case int:	
	// ...一些操作	
case cbsStruct: // 自定义的结构体	
	// ...一些操作

// ...
}
ここには : 多くの型があり、この関数を記述するのは非常に長くなり、カスタム型も存在する可能性があります。つまり、将来この判断を変更する必要がある可能性があります。 、値がどの型に属するかを知る方法がないためです。 未知の型を見破ることができない場合、上記のコードは実際にはあまり合理的ではありません。現時点では、それに対処するために Reflection が必要です。。 1. 変数の内部情報を取得する reflect は、インターフェイス変数の内容にアクセスするための 2 つのタイプを提供します: Type
何か問題は見つかりましたか? 問題があります
Reflection では、インターフェイスから TypeOf 関数と ValueOf 関数を使用して対象オブジェクトの情報を取得し、目的を簡単に完了できます3. リフレクションでは具体的に何ができるのでしょうか?
Function

reflect.ValueOf()

入力パラメータ インターフェイスのデータの値を取得する空の場合は、

0
を返します <- 0

reflect.TypeOf()

の値を動的に取得します。入力パラメータ インターフェイス Type、空の場合は

nil

を返します <- nil であることに注意してください

##上記のコード

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var name string = "咖啡色的羊驼"

	// TypeOf会返回目标数据的类型,比如int/float/struct/指针等
	reflectType := reflect.TypeOf(name)

	// valueOf返回目标数据的的值,比如上文的"咖啡色的羊驼"
	reflectValue := reflect.ValueOf(name)

	fmt.Println("type: ", reflectType)
	fmt.Println("value: ", reflectValue)
}

出力:
type:  string
value:  咖啡色的羊驼

より深い: 上記の操作が発生すると、リフレクションは「インターフェイス型変数」を「リフレクトされたインターフェイス型変数」に変換します。たとえば、上記は実際には、reflect.Value とreflect.Type のインターフェイスを返します。 。 物体。 (IDE に従って、関連する関数の戻り値の型を追跡することで知ることができます)

2.構造体の反映

package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Id   int
	Name string
}

func (s Student) Hello(){
	fmt.Println("我是一个学生")
}

func main() {
	s := Student{Id: 1, Name: "咖啡色的羊驼"}

	// 获取目标对象
	t := reflect.TypeOf(s)
	// .Name()可以获取去这个类型的名称
	fmt.Println("这个类型的名称是:", t.Name())

	// 获取目标对象的值类型
	v := reflect.ValueOf(s)
	// .NumField()来获取其包含的字段的总数
	for i := 0; i < t.NumField(); i++ {
		// 从0开始获取Student所包含的key
		key := t.Field(i)

		// 通过interface方法来获取key所对应的值
		value := v.Field(i).Interface()

		fmt.Printf("第%d个字段是:%s:%v = %v \n", i+1, key.Name, key.Type, value)
	}

	// 通过.NumMethod()来获取Student里头的方法
	for i:=0;i<t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Printf("第%d个方法是:%s:%v\n", i+1, m.Name, m.Type)
	}
}

出力:

这个类型的名称是: Student
第1个字段是:Id:int = 1 
第2个字段是:Name:string = 咖啡色的羊驼 
第1个方法是:Hello:func(main.Student)

3 .匿名フィールドまたは埋め込みフィールドの反映

package main

import (
	"reflect"
	"fmt"
)

type Student struct {
	Id   int
	Name string
}

type People struct {
	Student // 匿名字段
}

func main() {
	p := People{Student{Id: 1, Name: "咖啡色的羊驼"}}

	t := reflect.TypeOf(p)
	// 这里需要加一个#号,可以把struct的详情都给打印出来
	// 会发现有Anonymous:true,说明是匿名字段
	fmt.Printf("%#v\n", t.Field(0))

	// 取出这个学生的名字的详情打印出来
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 1}))

	// 获取匿名字段的值的详情
	v := reflect.ValueOf(p)
	fmt.Printf("%#v\n", v.Field(0))
}

出力:

reflect.StructField{Name:"Student", PkgPath:"", Type:(*reflect.rtype)(0x10aade0), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}

reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(0x109f4e0), Tag:"", Offset:0x8, Index:[]int{1}, Anonymous:false}

main.Student{Id:1, Name:"咖啡色的羊驼"}

4.受信した型が必要な型であるかどうかを判断します

package main

import (
	"reflect"
	"fmt"
)

type Student struct {
	Id   int
	Name string
}

func main() {
	s := Student{Id: 1, Name: "咖啡色的羊驼"}
	t := reflect.TypeOf(s)

	// 通过.Kind()来判断对比的值是否是struct类型
	if k := t.Kind(); k == reflect.Struct {
		fmt.Println("bingo")
	}

	num := 1;
	numType := reflect.TypeOf(num)
	if k := numType.Kind(); k == reflect.Int {
		fmt.Println("bingo")
	}
}
出力:
bingo
bingo
######5. リフレクションによるコンテンツの変更######
package main

import (
	"reflect"
	"fmt"
)

type Student struct {
	Id   int
	Name string
}

func main() {
	s := &Student{Id: 1, Name: "咖啡色的羊驼"}

	v := reflect.ValueOf(s)

	// 修改值必须是指针类型否则不可行
	if v.Kind() != reflect.Ptr {
		fmt.Println("不是指针类型,没法进行修改操作")
		return
	}

	// 获取指针所指向的元素
	v = v.Elem()

	// 获取目标key的Value的封装
	name := v.FieldByName("Name")

	if name.Kind() == reflect.String {
		name.SetString("小学生")
	}

	fmt.Printf("%#v \n", *s)


	// 如果是整型的话
	test := 888
	testV := reflect.ValueOf(&test)
	testV.Elem().SetInt(666)
	fmt.Println(test)
}
###出力: ###
main.Student{Id:1, Name:"小学生"} 
666
######6. メソッドの呼び出しリフレクションによる# #####
package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Id   int
	Name string
}

func (s Student) EchoName(name string){
	fmt.Println("我的名字是:", name)
}

func main() {
	s := Student{Id: 1, Name: "咖啡色的羊驼"}

	v := reflect.ValueOf(s)

	// 获取方法控制权
	// 官方解释:返回v的名为name的方法的已绑定(到v的持有值的)状态的函数形式的Value封装
	mv := v.MethodByName("EchoName")
	// 拼凑参数
	args := []reflect.Value{reflect.ValueOf("咖啡色的羊驼")}

	// 调用函数
	mv.Call(args)
}
###出力: ###
我的名字是: 咖啡色的羊驼
#####4. リフレクションの小さなポイント######1. リフレクションを使用する場合、最初に値が操作対象は期待されるタイプであり、「割り当て」操作を実行できるかどうか、そうでない場合は、reflect パッケージが容赦なくパニックを生成します。 ######2. リフレクションは主に Golang のインターフェイス タイプに関連しており、インターフェイス タイプのみがリフレクションを持ちます。興味があれば、TypeOf と ValueOf を見てみると、パラメーターが渡されるときにインターフェース型に変換されていることがわかります。 ###rreeee#########

以上がGolangのリフレクションの詳しい説明(例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。