go reflect 反射的使用

参考 :http://c.biancheng.net/view/4407.html

反射是指在程序运行期对程序本身进行访问和修改的能力,程序在编译时变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时程序无法获取自身的信息

举个例子说明啥是反射呢?

就是比如 python getattr 函数类似,通过字段属性名 拿到字段对应的值。
或者 a = "xxx"
js 里面 map.xxx 也可以 map[a]

go 里面什么情况用反射

我现在想通过字段名的 字符串变量,获取结构体对应的字段值, 貌似只能用 xxx_struct.xxx 而不能像 js 里面那样 xxx_struct["xxx"] , 那就只能用 反射了。

go 怎么实现 反射

使用 内置包 reflect
reflect 定义了两个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两部分组成

reflect 反射 练习
  • 反射获取信息 reflect.TypeOf

返回的是 reflect.Type 类型
reflect.Type 对象可以访问任意值的类型信息, 有两个重要的 函数, Name() 返回Type 和 Kind() 返回 Kind 种类
reflect.TypeOf (xxx interface{}).Name() 返回定义
int、string、bool、float32 以及 使用 type 定义的类型名
reflect.TypeOf (xxx interface{}).Kind() 返回定义
int、string、bool、float32 struct func 这种原始的类型名

普通类型获取反射类型

type A struct{} 
var a A
reflect.TypeOf(a).Name()   // A
reflect.TypeOf( a ).Kind()   //  struct

指针类型获取 反射类型

reflect.TypeOf(a).Elem().Name()/Kind() 

获取结构体的成员类型信息
(只是信息,并不能取到对应的值)
针对结构体,即如果 反射的 Kind() 返回的 是 struct ,那可以通过一下函数,获取它成员的信息

  • reflect.TypeOf (xxx interface{}).NumField()
    返回结构体成员字段数量
NumField() int  

  • reflect.TypeOf (xxx interface{}).Field()
    返回索引对应的结构体字段的信息
Field(i int) StructField
  • reflect.TypeOf (xxx interface{}).FieldByName()
    返回字符串对应的结构体字段的信息
FieldByName(name string) (StructField, bool)
  • reflect.TypeOf (xxx interface{}).FieldByIndex()
    多层成员访问时,根据 []int 提供的每个结构体的字段索引,返回字段的信息
FieldByIndex(index []int) StructField
  • reflect.TypeOf (xxx interface{}).FieldByNameFunc()
    根据匹配函数匹配需要的字段
FieldByNameFunc(match func(string) bool) (StructField,bool)

说明一下, 上面函数返回为 StructField 对象(Field, FieldByName, FieldByIndex, FieldByNameFunc ),StructField 对象具有以下属性

StructField 对象结构体字段

type StructField struct {
    Name string          // 字段名
    PkgPath string       // 字段路径
    Type      Type       // 字段反射类型对象,  字段本身的反射类型对象,类型为 
// reflect.Type,可以进一步获取字段的类型信息, 像递归了
    Tag       StructTag  // 字段的结构体标签
    Offset    uintptr    // 字段在结构体中的相对偏移
    Index     []int      // Type.FieldByIndex中的返回的索引值
    Anonymous bool       // 是否为匿名字段
}

举个例子说明获取结构体的字段信息

func main(){
    type girl struct{
        name string `json:"nikname"`
        age int
        high int

    }
    var a = girl{"小莲", 28, 165}
    reflect_type := reflect.TypeOf(a)
    fmt.Println( "Name():", reflect_type.Name(), "kind():", reflect_type.Kind())

    kind := reflect_type.Kind()
    if kind == reflect.Struct{
        fmt.Printf("是结构体\n")
        // 遍历获取名称, Field 通常和 NumField 以前搭配使用, 遍历结构体, 这
// 里仅获取结构体成员信息,并没有获取值
        for i := 0; i < reflect_type.NumField(); i++{
            fmt.Printf("index: %v, file name: %v\n", i, reflect_type.Field(i).Name)
        }

        // 通过字段名字获取字段信息.
        if info, ok := reflect_type.FieldByName("name"); ok{
            fmt.Printf("name is :%v, tag is: %v \n", info.Name, info.Tag.Get("json"))
        }

    }

}

>
Name(): girl kind(): struct
是结构体
index: 0, file name: name
index: 1, file name: age
index: 2, file name: high
name is :name, tag is: nikname 

上面提到了 结构体的反射对象 StructField 里面有个 Struct Tag, 我们来看看这个 TAG 里面是神马东西把:

字段的额外信息, 这些信息都是静态的,无须实例化结构体,可以通过反射获取到

书写结构:

`key1:"value1" key2:"value2"`

结构体标签由一个或多个键值对组成;键与值使用冒号分隔,值用双引号括起来;键值对之间使用一个空格分隔, 这个格式很严格,有地方多一个空格都不会是期望的结果

取出 key 对应值:

reflect_type.FieldByName("xx").Tag.Get("json")   

判断 key 是不是存在:
Lookup(key)

func (tag StructTag) Lookup(key string) (value string, ok bool)
reflect_type.FieldByName("xx").Tag.Lookup("json")   
  • 反射获取值 reflect.ValueOf

普通类型获取反射类型

value := reflect.ValueOf(rawValue)

返回 reflect.Value 类型
reflect.Value 是一些反射操作的重要类型,如反射调用函数

reflect.Value 对象所具有的方法

  • 将值以 interface{} 类型返回
Interface() interface {}
  • 将值以 int 类型返回(所有有符号整型均可以此方式返回)
Int() int64
  • 值以 uint 类型返回(所有无符号整型均可以此方式返回)
Uint() uint64
  • 值以双精度(float64)类型返回,所有浮点数(float32、float64)均可以此方式返回
Float() float64
  • 将值以 bool 类型返回
Bool() bool
  • 将值以字节数组 []bytes 类型返回
Bytes() []bytes
  • 将值以字符串类型返回
String() string 

结构体反射获取值
方法如下, 和获取信息的一样,子不过,获取的 是 Value 对象,不是 StructField 对象

  • Field(i int) Value
  • NumField() int
  • FieldByName(name string) Value
  • FieldByIndex(index []int) Value
  • FieldByNameFunc(match func(string) bool) Value

关于 值类型的方法参考:
https://golang.google.cn/pkg/reflect/#Value

反射修改值

reflect.Value 修改值得方法(和 获取值是对应的):

Setlnt(x int64)   SetUint(x uint64)  SetFloat(x float64) SetBool(x bool)  
SetBytes(x []byte   SetString(x string)  

可以被修改的条件:

传入地址
var a int = 1024
valueOfA := reflect.ValueOf(&a)
valueOfA = valueOfA.Elem()
valueOfA.SetInt(1)

结构体成员中,字段可导出
type dog struct {
            LegCount int
    }
valueOfDog := reflect.ValueOf(&dog{})
valueOfDog = valueOfDog.Elem()
vLegCount := valueOfDog.FieldByName("LegCount")
vLegCount.SetInt(4)

你可能感兴趣的:(go reflect 反射的使用)