Maison  >  Article  >  développement back-end  >  Explication détaillée de la réflexion de Golang (exemple)

Explication détaillée de la réflexion de Golang (exemple)

藏色散人
藏色散人avant
2020-09-08 09:21:233934parcourir

Ce qui suit est une introduction détaillée à Golang tirée du tutoriel Golang rubrique Réflexion (exemple), j'espère que cela sera utile à des amis dans le besoin !

Explication détaillée de la réflexion de Golang (exemple)

Préface

La réflexion a ses merveilleuses utilisations dans de nombreuses langues. En informatique, la réflexion fait référence à une classe d'applications qui permettent des attaques auto-descriptives et des attaques auto-contrôlées.

Cet article enregistrera les notes de l’auteur sur la réflexion de Golang.

Après 10 secondes, les points de connaissances suivants seront proches de vous :
1. Introduction à la réflexion
Pourquoi utiliser la réflexion ?
3. Que peut faire exactement la réflexion

Texte

1. Introduction à la réflexion

Golang fournit un mécanisme qui ne connaît pas le type au moment de la compilation. Dans le cas de , vous pouvez mettre à jour les variables, exécuterafficher les valeurs, appeler des méthodes et opérer directement sur leurs dispositions Le mécanisme s'appelle la réflexion.

2.Pourquoi utiliser la réflexion ?

Par exemple, nous avons parfois besoin d'une fonction capable de gérer différents types de valeurs. Sans connaître le type, vous pourriez écrire :

// 伪代码
switch value := value.(type) {
case string:
	// ...一些操作
case int:	
	// ...一些操作	
case cbsStruct: // 自定义的结构体	
	// ...一些操作

// ...
}

Avez-vous rencontré des problèmes ?
Il y a un problème ici : il existe de nombreux types, cette fonction sera très longue à écrire, et il peut aussi y avoir des types personnalisés, ce qui signifie que ce jugement devra peut-être être modifié dans le futur , car il n'y a aucun moyen de savoir. On ne sait pas à quel type appartient la valeur.

Lorsque vous ne pouvez pas voir à travers un type inconnu, le code ci-dessus n'est en fait pas très raisonnable. Pour le moment, vous avez besoin de Reflection pour vous aider à le gérer. Fonctions TypeOf et ValueOf depuis l'interface. Obtenez les informations de l'objet cible et accomplissez facilement l'objectif .

3. Que peut faire exactement la réflexion ?

1. Obtenir des informations internes sur les variables

reflect propose deux types pour accéder au contenu des variables d'interface :

Type Fonction
reflect.ValueOf() Obtenir la valeur de la donnée dans l'interface des paramètres d'entrée, si elle est vide, renvoie 0
类型 作用
reflect.ValueOf() 获取输入参数接口中的数据的值,如果为空则返回0 <- 注意是0
reflect.TypeOf() 动态获取输入参数接口中的值的类型,如果为空则返回nil <- 注意是nil
<- Notez qu'elle est 0
reflect.TypeOf( ) Obtenez dynamiquement le type de la valeur dans l'interface des paramètres d'entrée, si elle est vide, retournez

nil

<- Notez qu'elle est nulle

Le code ci-dessus

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)
}

Sortie :

type:  string
value:  咖啡色的羊驼
Un niveau plus profond : lorsque l'opération ci-dessus se produit, la réflexion convertit la "variable du type d'interface" dans la "variable du type d'interface réfléchi", par exemple, ce qui précède renvoie en fait les objets d'interface de réflexion.Value et réflexion.Type. (Vous pouvez le savoir en suivant le type de retour de la fonction concernée selon l'EDI)

2.Réflexion de la structure

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)
	}
}
Sortie :

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

3 .Réflexion de champs anonymes ou intégrés

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))
}
Sortie :

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 Déterminer si le type entrant est le type que nous voulons

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")
	}
}
Sortie :

bingo
bingo

5. Modifier le contenu par réflexion

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)
}
Sortie :

main.Student{Id:1, Name:"小学生"} 
666

6. par réflexion

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)
}

Sortie :

我的名字是: 咖啡色的羊驼

##4>Quelques petits points de réflexion

1 Lorsque vous utilisez la réflexion, vous devez d'abord déterminer si la valeur. sur lequel opérer est le type attendu, si l'opération "d'affectation" peut être effectuée, sinon le package de réflexion générera une panique sans pitié.

2. La réflexion est principalement liée au type d'interface de Golang. Si vous êtes intéressé, vous pouvez jeter un œil à TypeOf et ValueOf, et vous constaterez que lorsque les paramètres sont transmis, ils ont été convertis en types d'interface.
// 以下为截取的源代码
func TypeOf(i interface{}) Type {
	eface := *(*emptyInterface)(unsafe.Pointer(&i))
	return toType(eface.typ)
}

func ValueOf(i interface{}) Value {
	if i == nil {
		return Value{}
	}
	escapes(i)

	return unpackEface(i)
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer