Go reflect初探

Go reflect初探在计算机科学中 反射是指计算机程序在运行时 Runtime 可以访问 检测和修改它本身状态或行为的一种能力 用比喻来说 那种程序能够 观察 并且修改自己的行为 要注意反射和内省 typeintrospe 的区别 对应于变量 也就是围绕着它的类型 type 和值 value 进行展开 Go 的空接口概念 反射可以发挥很大的威力 两个重要类型 reflect Type re

两个重要类型

  • reflect.Type(reflect.Typeof()获得)
  • reflect.Value(reflect.Value()获得)

Type的一些方法

  • String
  • Name 都以字符串的形式返回结构名,只是Name包括包名
  • Field(index) 根据索引获得字段,返回的是StructField(字段也有类型,当然包含一个reflect.Type的字段)
  • NumField 返回的结构的字段数
  • FieldByName 根据字段名获得字段

带Field的方法是获取结构体字段信息的。

type Foo struct { X string Y int } func main() { var q = Foo{} var f interface{} = q t := reflect.TypeOf(f) for i := 0; i < t.NumField(); i++ { field := t.Field(i) fmt.Println(field.Name, field.Type.Name())// output: X Y string int } fi, _ := t.FieldByName("Y") fmt.Println(fi.Name) output: Y }

结构体不光有字段,还有方法,所以Go也提供了Method的一系列函数
– NumMethod
– Method
– FieldByNameFunc


Kind方法 返回对象的基本类型,如果是个结构体就返回struct。
有如下基本返回值

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 )

大体可以这样使用

func main() { var q = []int{ 
  1, 2, 3, 4} f := reflect.ValueOf(q) if f.Kind() == reflect.Slice { if fv, ok := f.Interface().([]int); ok { fmt.Println(fv) } } }

Value的一些方法

Value更关注的是接口值,而不是类型的值

  • Field 返回的仍是一个Value
  • Interface 获得接口值,+ 断言进行类型转换
  • NumField 同上Type
func main() { var q = Foo{ 
  "1234", 123} var f interface{ 
   } = q t := reflect.ValueOf(f) for i := 0; i < t.NumField(); i++ { field := t.Field(i) fmt.Println(field.Interface()) } field := t.Field(0) v, _ := field.Interface().(string) fmt.Println(v) }

可以看到Value和Type有类似的地方
但我们有对改变Value的需求,很少有改变Type的需求。所以Value会有跟多的方法

一系列Set操作

  • Set
  • SetString
  • SetBytes
  • SetInt

  • 但是没有提供SetSlice >_<!
func main() { var q = Foo{ 
  "1234", 123} var f interface{ 
   } = &q reflect.ValueOf(f).Elem().Field(0).SetString("4321") fmt.Println(q)// output:{4321 123} } 

练习:怎么给slice加一个Insert方法呢?而不用丑陋的两次append….

解答 func Insert(slice interface{}, pos int, value interface{}) interface{} { v := reflect.ValueOf(slice) ne := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(value)), 1, 1) ne.Index(0).Set(reflect.ValueOf(value)) v = reflect.AppendSlice(v.Slice(0, pos), reflect.AppendSlice(ne, v.Slice(pos, v.Len()))) return v.Interface() } func main() { slice := []int{ 
   1, 2} fmt.Println(Insert(slice, 1, 99)) slice2 := []string{ 
   "a", "c", "d"} slice2 = Insert(slice2, 0, "b").([]string) fmt.Println(Insert(slice2, 4, "e")) } 

做下性能测试:

func Insert(slice interface{}, pos int, value interface{}) interface{} { v := reflect.ValueOf(slice) ne := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(value)), 1, 1) ne.Index(0).Set(reflect.ValueOf(value)) v = reflect.AppendSlice(v.Slice(0, pos), reflect.AppendSlice(ne, v.Slice(pos, v.Len()))) return v.Interface() } func main() { slice := []int{} slice2 := []int{} t0 := time.Now() for i := 1; i < 10000; i++ { slice = append(slice[:0], append([]int{i}, slice[0:]...)...) } t1 := time.Now() for i := 1; i < 10000; i++ { slice2 = Insert(slice2, 0, i).([]int) } t2 := time.Now() fmt.Println(t2.Sub(t1), t1.Sub(t0)) }

输出:

215.ms 138.ms

连续插入一万个,使用反射和不使用消耗时间差了一倍。但我觉得还是可以接受的。>_<….对于性能要求不高的的地方,用用反射也没什么不可啊!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232547.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • PS2手柄遥控Arduino小车[通俗易懂]

    PS2手柄遥控Arduino小车[通俗易懂]使用手柄遥控小车是经常要用到的,看到PS2手柄很6,就拿来尝试一下。PS2手柄是索尼的PlayStation2游戏机的遥控手柄,因为这款手柄性价比较高,按键丰富,方便扩展到其它应用中,后来有人将其通讯协议破解,使得手柄可以用在遥控其他电器上,比如遥控控制机器人小车。最主要的是这款手柄,拿来就可以用,有人已经将其通讯协议破解了。具体可以参考极客工坊。其PS2X_lib库,可以参见Github

    2022年6月14日
    42
  • 使用instsrv.exe和srvany.exe创建windows服务[通俗易懂]

    使用instsrv.exe和srvany.exe创建windows服务[通俗易懂]srvany.exe是MicrosoftWindowsResourceKits工具集的一个实用的小工具,用于将任何EXE程序作为Windows服务运行。也就是说srvany只是其注册程序的服务外壳,这个特性对于我们来说非常实用,我们可以通过它让我们的程序以SYSTEM账户启动,或者实现随机器启动而自启动,也可以隐藏不必要的窗口,比如说控制台窗口等等。         将srvany.e

    2022年6月2日
    34
  • 什么是高维数据可视化的降维方法_数据降维具体算法有哪几种

    什么是高维数据可视化的降维方法_数据降维具体算法有哪几种&amp;amp;emsp;&amp;amp;emsp;t-SNE是目前来说效果最好的数据降维与可视化方法,但是它的缺点也很明显,比如:占内存大,运行时间长。但是,当我们想要对高维数据进行分类,又不清楚这个数据集有没有很好的可分性(即同类之间间隔小,异类之间间隔大),可以通过t-SNE投影到2维或者3维的空间中观察一下。如果在低维空间中具有可分性,则数据是可分的;如果在高维空间中不具有可分性,可能是数据不可分,也可能仅仅是因为不能投影到低维空间。

    2022年8月31日
    2
  • noip2012借教室_noip小学组

    noip2012借教室_noip小学组这个题首先很容易想到枚举1-m,再一个一个加起来,判断一下(最直白的暴力)于是又很容易想到用差分数组可以优化一下。就像这样#include<iostream>#include<cstdio>usingnamespacestd;constintmaxn=1000005;intd[maxn],s[maxn],t[maxn],r[maxn];…

    2022年8月22日
    5
  • 一级倒立摆装置_智能控制倒立摆

    一级倒立摆装置_智能控制倒立摆一级倒立摆装置

    2022年8月18日
    7
  • miRNA几大常用的数据库

    miRNA几大常用的数据库

    2022年2月24日
    48

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号