notas ir estudar o desenvolvimento do núcleo (Eva) - Reflexão

uso local de reflexão

  1. Quando a serialização e deserialização, se sequências desejadas nome de campo estrutura é convertido para maiúsculas para minúsculas, json:"xxx"aqui utiliza reflexão.
  2. Duas variáveis função anônima, um definido função adaptador como interface unitária:
    a função do adaptador: o nome da função é assumida anônima <nome função anônima>, os parâmetros de função anônima a, b ... do FUNC função de adaptador (<nome da função anônima> ,, a b ...)
    que é criar um modelo e nome da função função anônima anônima nos parâmetros de função são passados como uma função adaptador parâmetro.
  3. Refletindo o valor que eles podem ir para desenvolver o quadro.

princípio reflexão

  1. Refletindo adquiriu dinamicamente durante a execução várias informações variáveis, tais como o tipo do tipo variável, categoria tipo.
    Se o tipo de categoria e o tipo de dados são comuns, nenhuma diferença;
    se for uma estrutura de tipos e categorias de variáveis são diferentes;

  2. Pela reflexão, pode modificar o valor da variável, os métodos associados pode ser chamado.

  3. Use reflexivo necessário importar "refletir"

Aplicação de reflexão

  1. Comumente usadas duas funções: reflect.TypeOf (<variável>); reflect.ValueOf (<variável>)

  2. Use caso ilustra, casos posteriores têm notas explicativas.

    Demo 1: os tipos de dados básicos ≒ de interface {} ≒ reflect.Value

    package main
    import (
    	"fmt"
    	"reflect"
    )
    func main() {
    	var num int = 100
    	/*
    	问题一:
    	通过反射拿到num的rtype和rvalue
    	注意区分反射拿到的值前面加个r做区分,reflect.rtype和type不是同一个类型
    	这些*reflect.rtype 或 reflect.Value 是有方法的,和普通数据类型是不一样的。
    	*/
    	rty := reflect.TypeOf(num)           // int 注意这个int不是普通数据类型int,是有很多方法的
    	rval := reflect.ValueOf(num)         // 100 注意这个100不是普通值为100,是有很多方法的
    	fmt.Printf("%T %v\n",rty,rty)   //*reflect.rtype
    	fmt.Printf("%T %v\n",rval,rval)  // reflect.Value
    
    	/*问题二:
    	举例说明,rval如果是int类型,那么可以加减乘除,下面验证
    	 */
    	n1 := 10
    	n2 := 2 + n1
    	fmt.Println(n2)
    	//fmt.Println(n2 + rval)  //invalid operation: n2 + rval (mismatched types int and reflect.Value)
    	/*
    	如何解决上述问题
    	func (v Value) IsNil() bool
    	func (v Value) Kind() Kind
    	func (v Value) Type() Type
    	func (v Value) Convert(t Type) Value
    	func (v Value) Elem() Value
    	func (v Value) Bool() bool
    	func (v Value) Int() int64
    	 */
    	fmt.Println(int64(n2) + rval.Int())  //提供将reflect.Value转化为int64的方法,这样强转一下就好了
    
    	/*
    	问题三:
    	如何将reflect.Value转换为最初的int:只需要将reflect.Value转为空接口,再把空接口断言成需要转换的数据类型即可
    	 */
    	num_ori := rval.Interface().(int)
    	fmt.Printf("%T %v\n",num_ori,num_ori)  //int 100
    }
    

    Demonstração 2: Estrutura tipo ≒ de interface {} ≒ reflect.Value

    package main
    import (
    	"fmt"
    	"reflect"
    )
    type Kunkun struct {
    	Name string
    	Age int
    	Skill string
    }
    func main() {
    	/*
    	定义一个结构体实例caixukun,通过反射拿到type和value
    	 */
    	var caixukun = Kunkun{"蔡徐坤",20,"Ctrl"}
    	cxkrty := reflect.TypeOf(caixukun)
    	cxkrval := reflect.ValueOf(caixukun)
    	fmt.Printf("%T %v\n",cxkrty,cxkrty)   // *reflect.rtype  main.Kunkun
    	fmt.Printf("%T %v\n",cxkrval,cxkrval)  // reflect.Value {蔡徐坤 20 Ctrl} 仅在运行时知道类型,编译阶段过不去
    
    	//将拿到的值转换成空接口,如果这是想取cxkival中的字段值是无法取出来的
    	cxkival := cxkrval.Interface()
    	fmt.Printf("%T %v\n",cxkival,cxkival) //main.Kunkun {蔡徐坤 20 Ctrl}
    	fmt.Println(caixukun.Name)
    	//fmt.Println(cxkival.Name)  //cxkival.Name undefined (type interface {} is interface with no methods)
    
    	//将空接口类型断言成结构体类型就可以使用字段了
    	cxk_ori, ok := cxkival.(Kunkun)  //已经将空接口类型数据断言成Kunkun结构体
    	if ok {
    		fmt.Println("成功断言取出字段名称: ",cxk_ori.Name)    //蔡徐坤
    	}
    }
    

notas de reflexão e detalhes

  1. reflect.Value.Kind (), reflect.rType.Kind () Obtém um retorno variável classe é uma constante, diferentes em termos de tipo, categoria é um conjunto de tipos.

    var num int = 10    // type: int , Kind: int  这是普通数据类型
    var cxk Kunkun      // type: Kunkun , Kind: Struct 结构体就有宏观和微观概念了,例如Kunkun是自定义type,是结构体的一类,Struct包含Kunkun这种结构体。
    
  2. Uma forma reflexiva para obter o valor da variável, o tipo de dados corresponde aos requisitos, caso contrário, eles vão pânico .

  3. Valor de uma variável modificada pela reflexão, veja abaixo demonstra dois:

    Demo 1: alterando o valor da variável de uma reflexão comum

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    func main() {
    	/*
    	1. 通过反射修改普通变量的值
    	2. 通过反射修改结构体实例的值
    	 */
    	//var cxk = Kunkun{"蔡徐坤",20,"Ctrl"}
    	var num int = 100
    	//使用反射修改普通变量的值,如果要改变变量值,必须传递地址,通过改变内存地址中的值完成变量改变
    	rNum := reflect.ValueOf(num)
    	fmt.Printf("%T %v\n",rNum,rNum)
    	//rNum.SetInt(20)            	   //reflect.Value.SetInt using unaddressable value,因为不是地址格式的数据所以不行
    	//rNum.Elem().SetInt(20)          //把num变成20
    	fmt.Printf("%T %v\n",num,num)   //这样改变肯定无效,因为不是指针格式
    
    	//下面为正确做法
    	rNum1 := reflect.ValueOf(&num)   //必须是地址,不然没有意义,无法改变num的值
    	fmt.Printf("%T %v\n",rNum1,rNum1)
    	rNum1.Elem().SetInt(20)          //把num变成20,rNum1为地址,rNum1.Elem()为一个value,Elem()用的最多,一定要注意
    	fmt.Printf("%T %v\n",num,num)    //如果没有Elem(),unaddressable value panic
    }
    

    Demonstração 2: um valor obtido por alteração da estrutura do reflector campo

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type kunkun struct {
    	Name string
    	Age int
    	Skill string
    }
    
    func main() {
    	/*
    	上面理论讲的很清楚了,下方与上方修改普通变量几乎没有区别,唯一在于传入的地址变成了字段 &(cxk.Skill)
    	 */
    	var cxk = kunkun{"蔡徐坤",20,"Ctrl"}
    	rCxk := reflect.ValueOf(&(cxk.Skill))
    	rCxk.Elem().SetString("唱跳rap篮球")      //相当于改变了原来结构体实例中的技能变为 "唱跳rap篮球"
    	fmt.Println(cxk.Skill)
    }
    

★★★ reflexo de melhores práticas

Caso: usando a reflexão para atravessar a estrutura do campo, a estrutura da chamada de método, e obtendo uma estrutura de tag valor.

package main

import (
	"fmt"
	"reflect"
)

//kunkun结构体
type caixukun struct {
	Name string   `json:"name"`
	Age int	      `json:"age"`
	Skill string
}
func (c caixukun) Intro() {      // reflect.Value.Method()中 i=0
	fmt.Println("大家好,我是练习时长两年半的练习生cxk!")
}
func (c caixukun) Dance() {      // reflect.Value.Method()中 i=1
	fmt.Println("鸡你太美~~丁丁丁丁丁丁丁~鸡你太美~~~丁丁丁丁丁丁丁丁~~")
}
func (c caixukun) Set(n1 int,n2 int) int {      // // reflect.Value.Method()中 i=2
	return n1 + n2
}

func Ref(cxk interface{}) {
	rty := reflect.TypeOf(cxk)    //获取结构体变量的反射类型
	rval := reflect.ValueOf(cxk)  //获取结构体变量的反射值
	rkd := rval.Kind()            //获取结构体变量的类型常量
	//fmt.Printf("%T %v\n",rty,rty)   //*reflect.rtype main.caixukun
	//fmt.Printf("%T %v\n",rval,rval) //reflect.Value {蔡徐坤 20 Ctrl}
	//fmt.Printf("%T %v\n",rkd,rkd)   //reflect.Kind struct
	if rkd != reflect.Struct {          //Struct为常量比较
		fmt.Println("unexpect struct, re-input the correct struct, exit Program~")
		return
	}

	//获取结构体实例所有字段和值
	Fnum := rval.NumField()    //常用的一个方法,获得结构体方法数量,类似len()和 cap() 3个字段
	//接下来演示如何拿到结构体实例的字段和值
	for i := 0 ; i < Fnum ; i++ {
		/*
		Name string   `json:"name"`   //有tag
		Age int	      `json:"age"`    //有tag
		Skill string                  //无tag
		*/
		fmt.Printf("字段索引值为%d,字段值为%v\n",i,rval.Field(i)) //reflect.Value.Field(x)获得字段值
		//检查结构体实例字段的tag标签
		tagRval := rty.Field(i).Tag.Get("json")
		fmt.Printf("第%d个字段为%v,对应的tag为%v\n",i,rval.Field(i),tagRval)
	}

	//获取结构体实例有多少个方法以及方法调用
	methods := rval.NumMethod()
	fmt.Printf("结构体实例存在%d个方法\n",methods)
	
	//reflect.Value.Method(x int)方法中,方法索引排序并不是按照结构体代码由上到下,而是按照方法首字母ASCII代码码值进行
	//所以方法0为:Dance(),方法1为:Intro(),方法2为:Set(xxx),如果方法中本身不传参,Call中必须填入(nil)
	rval.Method(1).Call(nil)   //调用Intro方法: 大家好,我是练习时长两年半的练习生cxk!
	rval.Method(0).Call(nil)   //调用Dance方法: 鸡你太美~~...
	
	//对于要传递参数的方法,传进call()中的是一个[]reflect.Value切片,所以需要先定义切片
	var slice []reflect.Value
	slice = append(slice,reflect.ValueOf(30))   //传第一个参数 进切片
	slice = append(slice,reflect.ValueOf(20))   //传第二个参数 进切片
	fmt.Println(rval.Method(2).Call(slice)[0])  //返回值只有一个值,也是一个切片,所以只需要接收切片第一个值[0]

}

func main() {
	/*
	使用反射来遍历结构体字段,调用结构体的方法,并获得结构体的标签值
	两个重要方法
	1. reflect.Value.Method() :
	func (v Value) Method(i int) Value
	默认按照传入结构体实例的方法名排序对应的i值,初始值i=0
	见上方结构体方法注释,三个方法,分别为方法0,1,2,返回值是一个reflect.Value
	2. reflect.Value.Call() :
	func (v Value) Call(in []Value) []Value
	通过Method获取的几个Value,作为参数形式传入Call()中,调用几种方法,注意[]value为reflect.Value的切片
	 */
	var cxk = caixukun{"蔡徐坤",20,"Ctrl"}
	Ref(cxk)
}
Publicado 49 artigos originais · ganhou elogios 18 · vista 3996

Acho que você gosta

Origin blog.csdn.net/weixin_41047549/article/details/90579722
Recomendado
Clasificación