• golang 反射


    reflect包

    在Go语言的反射机制中,任何接口值都由是一个具体类型具体类型的值两部分组成的(我们在上一篇接口的博客中有介绍相关概念)。 在Go语言中反射的相关功能由内置的reflect包提供,任意接口值在反射中都可以理解为由reflect.Typereflect.Value两部分组成,并且reflect包提供了reflect.TypeOfreflect.ValueOf两个函数来获取任意对象的Value和Type。

    在反射中关于类型还划分为两种:类型(Type)种类(Kind)。因为在Go语言中我们可以使用type关键字构造很多自定义类型,而种类(Kind)就是指底层的类型,但在反射中,当需要区分指针、结构体等大品种的类型时,就会用到种类(Kind)。 举个例子,我们定义了两个指针类型和两个结构体类型,通过反射查看它们的类型和种类。

    func reflectType(e  interface {}) {
        tpe := reflect.TypeOf(e)
        fmt.Println( "type:" , tpe)
        fmt.Printf( "name:%v  kind:%v \n" , tpe.Name(), tpe.Kind())   
    }
      func main(){
        k := 1204.58 reflectType(k)  //type: float64 //name:float64  kind:float64 g := "zhansan" reflectType(g)  //type: string //name:string  kind:string }

    Go语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回

    reflect包中定义的Kind类型如下:

     1 type Kind uint
     2 const (
     3     Invalid Kind = iota  // 非法类型
     4     Bool                 // 布尔型
     5     Int                  // 有符号整型
     6     Int8                 // 有符号8位整型
     7     Int16                // 有符号16位整型
     8     Int32                // 有符号32位整型
     9     Int64                // 有符号64位整型
    10     Uint                 // 无符号整型
    11     Uint8                // 无符号8位整型
    12     Uint16               // 无符号16位整型
    13     Uint32               // 无符号32位整型
    14     Uint64               // 无符号64位整型
    15     Uintptr              // 指针
    16     Float32              // 单精度浮点数
    17     Float64              // 双精度浮点数
    18     Complex64            // 64位复数类型
    19     Complex128           // 128位复数类型
    20     Array                // 数组
    21     Chan                 // 通道
    22     Func                 // 函数
    23     Interface            // 接口
    24     Map                  // 映射
    25     Ptr                  // 指针
    26     Slice                // 切片
    27     String               // 字符串
    28     Struct               // 结构体
    29     UnsafePointer        // 底层指针
    30 )

    通过 reflect.ValueOf 获取值

    func getreflect(e interface{}) {
        tpe := reflect.ValueOf(e)
        k := tpe.Kind()
        switch k {
        case reflect.String:
            fmt.Printf("value:%v\n", string(tpe.String()))
        case reflect.Int:
            fmt.Printf("value:%v\n", int(tpe.Int()))
        case reflect.Float64:
            fmt.Printf("value:%v\n", float64(tpe.Float()))
        case reflect.Bool:
            fmt.Printf("value:%v\n", bool(tpe.Bool()))
        }
    }

    想要在函数中通过反射修改变量的值,需要注意函数参数传递的是值拷贝,必须传递变量地址才能修改变量值。而反射中使用专有的Elem()方法来获取指针对应的值。

    func setvalue(e interface{}) {
        k := reflect.ValueOf(e)
        // 反射中使用 Elem()方法获取指针对应的值
        if k.Elem().Kind() == reflect.Float64 {
            k.Elem().SetFloat(float64(200.5))
        }
    }
    func main(){
      k := 1204.58
      fmt.Println(k) // 1204.58
      setvalue(&k)
      fmt.Println(k) //  200.5
    }

    isNil()和isValid()

    func (v Value) IsNil() bool

    IsNil()报告v持有的值是否为nil。v持有的值的分类必须是通道、函数、接口、映射、指针、切片之一;否则IsNil函数会导致panic。


    func (v Value) IsValid() bool

    IsValid()返回v是否持有一个值。如果v是Value零值会返回假,此时v除了IsValid、String、Kind之外的方法都会导致panic。

    func main() {
    	// *int类型空指针
    	var a *int
    	fmt.Println("var a *int IsNil:", reflect.ValueOf(a).IsNil())
    	// nil值
    	fmt.Println("nil IsValid:", reflect.ValueOf(nil).IsValid())
    	// 实例化一个匿名结构体
    	b := struct{}{}
    	// 尝试从结构体中查找"abc"字段
    	fmt.Println("不存在的结构体成员:", reflect.ValueOf(b).FieldByName("abc").IsValid())
    	// 尝试从结构体中查找"abc"方法
    	fmt.Println("不存在的结构体方法:", reflect.ValueOf(b).MethodByName("abc").IsValid())
    	// map
    	c := map[string]int{}
    	// 尝试从map中查找一个不存在的键
    	fmt.Println("map中不存在的键:", reflect.ValueOf(c).MapIndex(reflect.ValueOf("娜扎")).IsValid())
    }

    结构体反射

    任意值通过reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.Type)的NumField()Field()方法获得结构体成员的详细信息。

    reflect.Type中与获取结构体成员相关的的方法如下表所示。

    方法 说明
    Field(i int) StructField 根据索引,返回索引对应的结构体字段的信息。
    NumField() int 返回结构体成员字段数量。
    FieldByName(name string) (StructField, bool) 根据给定字符串返回字符串对应的结构体字段的信息。
    FieldByIndex(index []int) StructField 多层成员访问时,根据 []int 提供的每个结构体的字段索引,返回字段的信息。
    FieldByNameFunc(match func(string) bool) (StructField,bool) 根据传入的匹配函数匹配需要的字段。
    NumMethod() int 返回该类型的方法集中方法的数目
    Method(int) Method 返回该类型方法集中的第i个方法
    MethodByName(string)(Method, bool) 根据方法名返回该类型方法集中的方法

    StructField的定义如下:

    type StructField struct {
        // Name是字段的名字。PkgPath是非导出字段的包路径,对导出字段该字段为""。
        // 参见http://golang.org/ref/spec#Uniqueness_of_identifiers
        Name    string
        PkgPath string
        Type      Type      // 字段的类型
        Tag       StructTag // 字段的标签
        Offset    uintptr   // 字段在结构体中的字节偏移量
        Index     []int     // 用于Type.FieldByIndex时的索引切片
        Anonymous bool      // 是否匿名字段
    }

    实战 :

    type User struct { //创建一个user 类型的结构体
    	// gorm.Model
    	Name     string `json:"name"`
    	Age      int    `json:"age"`
    	Username string `json:"username"`
    	Password string `json:"password"`
    	Gender   string `json:"gender"`
    }
    
    func (user User) Setmyname() {
    	fmt.Println("我的名字叫", user.Name)
    }
    func (user User) Setmyage() {
    	fmt.Println("我的名字叫", user.Age)
    }
    func reflectType(e interface{}) {
    	tpe := reflect.TypeOf(e)
    	for i := 0; i < tpe.NumField(); i++ {
    		field := tpe.Field(i)
    		fmt.Printf("name:%v index:%d type:%v tag:%v\n", field.Name, field.Index[i], field.Type, field.Tag.Get("json"))
    	}
    }
    func main(){
        user := User{
    		Name:     "zhansan",
    		Age:      25,
    		Username: "root",
    		Password: "admin",
    		Gender:   "nan",
    	}
    	reflectType(user)
        //name:Name index:[0] type:8 tag:name
        //name:Age index:[1] type:8 tag:age
        //name:Username index:[2] type:8 tag:username
        //name:Password index:[3] type:8 tag:password
        //name:Gender index:[4] type:8 tag:gender
    }

        v := reflect.ValueOf(user)
    	t := reflect.TypeOf(user)
    	
    	for index := 0; index < v.NumMethod(); index++ {
    		methodType := v.Method(index).Type()
    		fmt.Printf("method name:%s\n", t.Method(index).Name)
    		fmt.Printf("method:%s\n", methodType)
    		var ref = []reflect.Value{}
    		v.Method(index).Call(ref)
    	}
  • 相关阅读:
    关于WPF程序引用(用到)的PresentationFramework.dll版本问题
    【转载】Jenkins在CentOS上安装部署
    关于2021/04/15实施3.0版本到中间层服务器发现IIS管理器的SVC无法浏览另类问题分析
    关于2021/03/02本地服务总线作业调度没起来问题分析
    【转】WCF服务部署到IIS7.5(备忘)
    Dapper参数化查询使用实例
    HIVE和HBASE区别
    Hadoop生态系统官网、下载地址、文档
    Hive中Sqoop的基本用法和常见问题
    读懂hadoop、hbase、hive、spark分布式系统架构
  • 原文地址:https://www.cnblogs.com/finghi/p/16324172.html
Copyright © 2020-2023  润新知