Reflect-Go 一分钟快速入门 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hetiansu5
V2EX    推广

Reflect-Go 一分钟快速入门

  •  
  •   hetiansu5 2020-01-10 16:54:29 +08:00 3889 次点击
    这是一个创建于 2112 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Reflect

    本文侧重讲解 reflect 反射的实践应用,适合新手初窥门径。

    reflect 两个基本功能

    • reflect.TypeOf() 动态获取输入数据的类型
    • reflect.ValueOf() 动态获取输入数据的值
    func TypeOf(i interface{}) Type func ValueOf(i interface{}) Value 

    通过 reflect.Type 和 reflect.Value 支持的方法,可以对输入的动态数据进行解析。 那么了解 reflect.Type 和 reflect.Value 提供的方法尤为重要,因为比较多,此介绍放在文末。

    reflect.Kind

    在 reflect.Type 和 reflect.Value 上调用 Kind()方法,可以得到 reflect.Kind 类型值,从而知道动态数据的类型。这个是动态解析的钥匙,通过反射后拿到具体的类型才能做相应的工作,逐层解析。

    const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer ) 

    解析流程

    • Ptr 指针和 Interface 通过调用 Elem()方法得到指向元素的值,再进入循环解析。
    • Slice、Array、Map、Struct 复合数据类型,通过各自的方法拿到他们组成类型值,再进入循环解析
    • 直到为基础数据类型或者 Func、Chan、UnsafePointer。 reflect 解析动态数据流程

    具体类型解析

    下述 demo 中默认

    rt = reflect.TypeOf(data) rv = reflect.ValueOf(data) 

    Struct

    //遍历结构体的 Field for i := 0; i < rt.NumField(); i++ { rt.Field(i) //第 i 个 Field 的 StructField rv.Filed(i) //第 i 个 Field 的 Value } //遍历结构体的方法 for i := 0; i < rt.NumMethod(); i++ { rt.Method(i) //第 i 个方法的 Method rv.Method(i) //第 i 个方法的 Value } 

    Map

    //遍历 Map 的 key 和 value for _, key := range rv.MapKeys() { //其中 key 为键的 Value rv.MapIndex(key) //键值的 Value } rv.Len() //map 的大小 rv.SetMapIndex() //map 索引赋值 

    Slice Array

    //遍历 Slice 或者 Array for i := 0; i < rv.Len(); i++ { rv.Index(i) //子元素的 Value } rv.Cap() //获取切片或者 Array 容量 rv.SetCap(i) //调整切片容量 rv.Slice(i, j) //返回切片 s[i:j]的 Value 

    Ptr Interface

    if !rv.IsNil() { rv.Elem() //指针或者 interface 实际指向元素 } 

    Bool Int Unit Float Complex String

    rv.Bool() //返回 bool rv.Int() //返回 int64 rv.Uint() //返回 uint64 rv.Float() //返回 float64 rv.Complex() //返回 complex128 rv.Sting() //返回 string //修改 Value 结构中的值,必须类型一致 rv.Set() rv.SetBool() rv.SetInt() rv.SetUint() rv.SetFloat() rv.SetComplex() rv.SetString() rv.SetBytes() 

    Func Chan UnsafePointer

    动态解析的时候,用得比较少,这里就不说了

    Type 和 Value 方法

    Type 和 Value 拥有的同名方法

    | Method | Type 返回类型 | Value 返回类型 | 备注 | | :---- | :---- | :---- | :---- | | Kind | Kind | Kind | 返回指定对象的 Kind 类型 | | NumMethod | int | int | 返回 struct 拥有的方法总数,包括 unexported 方法 | | MethodByName | Method | Value | 根据方法名找方法 | | Method | Method | Value | 返回第 i 个方法 | | NumField | int | int | 返回 struct 所包含的 field 数量 | | Field | StructField | Value |取 struct 结构的第 n 个 field | | FieldByIndex | StructField | Value |嵌套的方式取 struct 的 field,比如 v.FieldByIndex([]int{1,2})等价于 v.field(1).field(2) | | FieldByName | StructFiel,bool | Value | 返回名称匹配 match 函数的 field | | FieldByNameFunc | StructField,bool | Value | 返回名称匹配 match 函数的 field |

    Type 独有的方法

    | Method | 备注 | | :---- | :---- | |Align |分配内存时的内存对齐字节数 | |FieldAlign |作为 struct 的 field 时内存对齐字节数 | |Name |type 名 string 类型 | |PkgPath |包路径, "encoding/base64", 内置类型返回 empty string | |Size |该类型变量占用字节数 | |String |type 的 string 表示方式 | |Implements |判断该类型是否实现了某个接口 | |AssignableTo |判断该类型能否赋值给某个类型 | |ConvertibleTo |判断该类型能否转换为另外一种类型 | |Comparable |判断该类型变量是否可以比较 | |ChanDir |返回 channel 的方向 recv/send/double | |IsVariadic |判断函数是否接受可变参数 | |Elem |取该类型的元素 | |In |函数第 n 个入参 | |Out |函数第 n 个出参 | |NumIn |函数的入参数个数 | |NumOut |函数的出参个数 | |Key |返回 map 结构的 key 类型 Type | |Len |返回 array 的长度 |

    Value 独有的方法

    | Method | 备注 | | :---- | :---- | |Addr | v 的指针,前提时 CanAddr()返回 true | |Bool | 取值,布尔类型 | |Bytes | 取值,字节流 | |Call |调用函数 | |CallSlice |调用具有可变参的函数 | |CanAddr |判断能否取址 | |CanInterface |判断 Interface 方法能否使用 | |CanSet |判断 v 的值能否改变 | |Cap |判断容量 Array/Chan/Slice | |Close |关闭 Chan | |Complex | 取值,复数 | |Convert |返回将 v 转换位 type t 的结果 | |Elem | 返回 interface 包含或者 Ptr 指针的实际值 | |Float | 取值,浮点型 | |Index 索引操作 | Array/Slice/String | |Int | 取值,整型 | |Interface |将当前 value 以 interface{}形式返回 | |IsNil |判断是否为 nil,chan, func, interface, map, pointer, or slice value | |IsValid |是否是可操作的 Value,返回 false 表示为 zero Value | |Len |适用于 Array, Chan, Map, Slice, or String | |MapIndex |对 map 类型按 key 取值 | |MapKeys |map 类型的所有 key 的列表 | |OverflowComplex | 溢出判断 | |OverflowFloat | 溢出判断 | |OverflowInt | 溢出判断 | |OverflowUint | 溢出判断 | |Pointer |返回 uintptr 适用于 slice | |Recv | chan 接收 | |Send | chan 发送 | |Set | 将 x 赋值给 v,类型要匹配 | |SetBool | Bool 赋值,需要先判断 CanSet()为 true | |SetBytes | Bytes 赋值 | |SetCap | slice 调整切片容量 | |SetMapIndex | map 索引赋值 | |SetUint | Unit 赋值 | |SetPointer |unsafe.Pointer 赋值 | |SetString | String 赋值 | |Slice | return v[i:j] 适用于 Array/Slict/String | |String | return value 的 string 表示方法 | |TryRecv | chan 非阻塞接收 | |TrySend | chan 非阻塞发送 | |Type | 返回 value 的 Type | |UnsafeAddr | 返回指向 value 的 data 的指针 |

    引用链接

    Type 和 Value 方法: https://www.cnblogs.com/ksir16/p/9040656.html

    6 条回复    2020-01-13 09:57:04 +08:00
    hetiansu5
        1
    hetiansu5  
    OP
       2020-01-10 16:55:19 +08:00
    v2ex 的 markdown 不支持居然还不支持表格
    guonaihong
        2
    guonaihong  
       2020-01-11 14:36:42 +08:00
    难道,遇到和我一样喜欢玩 reflect 包的童鞋。。。
    guonaihong
        3
    guonaihong  
       2020-01-11 14:37:10 +08:00
    写错了,是难得。。。
    Aether
        4
    Aether  
       2020-01-11 15:23:27 +08:00
    我觉得所谓“实践运用”,不是罗列一堆枯燥的知识点,就像是把工具箱里的工具摆了一地,但却让人看得发呆。而是从修改椅子上一个转角开始,以一个常见的实例开始,讲述入手的思路,解决的方法选择,最后推导出为什么要使用一种效率更优美的方案,延展引入工具的讲解和实际操作,最后将问题加以解决。

    要做到这一点很难。
    hetiansu5
        5
    hetiansu5  
    OP
       2020-01-13 09:54:21 +08:00
    @guonaihong 嘿嘿。因为撸一个 URL Query String 的编码和解码器,顺便加深一下。
    hetiansu5
        6
    hetiansu5  
    OP
       2020-01-13 09:57:04 +08:00
    @Aether 嗯,现在还达不到这样的功力,一些粗浅的理解。蛮尝试写出来,也希望可以和大家多多交流。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     953 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:17 PVG 05:17 LAX 14:17 JFK 17:17
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86