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)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • reflection 反射(reflection)是程序在运行时通过检查其定义的变量和值获得对应的真实类型。 在计...
    JunChow520阅读 1,752评论 0 5
  • 目录 通过反射获取类型信息[https://www.cnblogs.com/itbsl/p/10551880.ht...
    gurlan阅读 520评论 0 0
  • reflect概述 反射是一种检查存储在 接口变量中的<值,类型>对 的机制,借助go反射包提供的reflect....
    斯嘎啦阅读 1,062评论 0 0
  • 一、认识反射 维基百科中的定义:在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改...
    Every_dawn阅读 1,572评论 0 0
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,520评论 28 53