go语言反射的总结

首先巴拉巴拉一下golang反射机制的三个定律

  • 1.反射可以从接口类型到反射类型对象
  • 2.反射可以从反射类型对象到接口类型
  • 3.修改反射类型变量的内部值需要保证其可设置性

reflect的基本使用

  • reflect.ValueOf(obj) 返回obj的Value(如果要对obj进行修改的话传入变量地址)
  • reflect.TypeOf(obj) 返回obj的对象类型
  • reflect.Indirect(value) 返回Value获取了该指针指向的值
  • reflect.New(typ Type) 返回一个新的type类型的对象

对象类型的基本操作

dataStruct := reflect.Indirect(reflect.ValueOf(obj))//获取对象的Value对象
dataStruct.Kind()//数据是什么类型:slice切面.Struct对象
dataStruct.NumField()//属性的个数
dataStruct.FieldByName("")//利用属性名获取属性
dataStruct.Field(1)//获取第几个属性
reflect.New(dataStruct.Type())//创建一个新的对象
dataStruct.Type()//对象的类型

属性的操作

dataStruct.FieldByName("")//利用属性名获取属性
dataStruct.Field(1)//获取第几个属性
fieldName := field.Name//属性的名称
fieldValue:=field.Interface()//获取属性值
bb := field.Tag//获取属性的标记
columnTag := bb.Get("column")//获取表中列的标记
field.Set(sliceValue)//给属性重新赋值

切片类型的基本操作

reflect.TypeOf(slice).Elem()//获取切片的Struct类型
reflect.New(reflect.TypeOf(slice).Elem())//创建一个新的切面包含对象类型
sliceValue := reflect.ValueOf([]int{1, 2, 3}) // 这里将slice转成reflect.Value类型

reflect的内置对象

  • Value

          Value       表示一个Go对象的值
          value.CanSet()返回值能否更改
          value.MethodByName("name")//根据方法名查找方法返回Value
          value.FieldByName("name")//根据属性名查找属性返回Value
          
          func (v Value) CanAddr() Value///这个方法是设置值的方法的基础,使用ValueOf()生成一个Value时,参数是值传递的,因此设置这个参数一点意义也没有。正确的方法是传入一个指针,然后调用Elem()方法来生成其指向的元素对应的Value对象
          func (v Value) Addr() Value//获得其地址  如果CanAddr()返回false,那么这个调用会panic
          func (v Value) UnsafeAddr() uintptr//和Addr()方法有同样的要求
          func (v Value) CanSet() bool//是否可以修改其值,一个值必须是可以获得地址且不能通过访问结构的非导出字段获得,方可被修改
          func (v Value) Set(x Value) //设置值   如果CanSet()返回false,那么panic
          func (v Value) Convert(t Type) Value//转换为其他类型的值 如果无法使用标准Go转换规则来转换,那么panic
          func (v Value) Iterface{} interface{}//以空接口类型获得值  如果Value是通过访问结构的非导出字段获得,panic
          func (v Value) IsValid() bool // 是否是一个合法的Value对象   只有零值才会返回false
          func (v Value) Kind() Kind      //* 所属的类型分类   零值会返回Invalid
          func (v Value) String() string//* 字符串格式   返回值的格式为<类型 值>
          func (v Value) Type() Type//类型
          * 方法集和方法
          func (v Value) NumMethod() int
          func (v Value) Method(index int) Value
          func (v Value) MethodByName(name string) Value
          //Type类型定义了同名方法,但是返回的是类型信息,这里返回的是值信息。Method()方法,如果v没有任何方法集,或者index越界,那么panic。MethodByName()方法,如果没有找到名为name的方法,那么返回一个零值
          *属性
          func (v Value) NumField() int   //结构字段数量
          func (v Value) Field(i int) Value       //使用索引来访问字段,索引从0开始,如果越界将panic
          func (v Value) FieldByName(name string) Value       //使用名称来访问字段,如果未找到那么返回false
          func (v Value)FieldByNameFunc(match func(string) bool) Value        //访问名称使得match函数返回true的字段,在同一个内嵌层次上,只能有一个字段使得match返回true。如果同一层次上多个字段使得match返回true,
                                                                              那么这些字段都认为是不符合要求的
          func FieldByIndex(index []int) Value        //这个方法使得访问结构的内嵌字段成为可能。将访问各个层次的字段的索引排列起来,就形成了一个[]int,参数index不可越界,否则panic 
          *函数类型值
          func (v Value) Call(in []Value)[]Value
          func (v Value) CallSlice(in []Value) []Value
                  注:Call()方法用来调用函数(参数可变或者固定),采用的是用户代码使用的调用格式。CallSlice()方法专门用于调用参数可变的函数,它采用了编译器使用的调用格式。这两种调用格式的区别在于:
                      u 对于参数固定的函数,两种格式没有任何区别,都是按照位置,将实参赋予形参
                      u 对于参数可变的函数,编译器格式会特别处理最后一个参数,将剩余的实参依次放入一个slice内,传递给可变形参的就是这个slice。
          func (v Value) Pointer() uintptr        //以uintptr返回函数的值,这个值并不能独一无二的识别一个函数,只是保证如果函数为nil,那么这个值为0
          *类型信息
          func ChanDir() ChanDir//判断通道的方向
          func Elem() Type//元素的类型
          *通道值
          func (v Value) IsNil() bool
          func (v Value) Pointer() uintptr    //以unitptr返回其值,没有使用unsafe.Pointer类型,所以不需要导入unsafe包
          func (v Value) Close()
          func (v Value) Len() int        //通道当前元素数量
          func (v Value) Cap() int        //通道的长度
          func (v Value) Send(x Value)         //发送一个值,x必表示一个可以赋值给通道元素类型的值
          func (v Value) TrySend(x Value) bool        //尝试以非阻塞的方式发送一个值,返回操作成功与否
          func (v Value) Recv() (Value,bool)      //接收一个值,如果通道已经关闭,返回一个Value零值。由于通道本身可能传输Value零值,所以必须额外使用一个布尔返回值来表示接收是否成功
          func (v Value) TryRecv() (Value,bool)       //尝试以非阻塞的方式接收一个值
          *slice
          func Elem() Type            //类型
          func (v Value) Len() int
          func (v Value) Cap() int
          func (v Value) IsNil() bool
          func (v Value) Pointer() uintptr
          func (v Value) Index(i int) Value   //访问某个元素
          func (v Value) Slice(i,j int) Value //访问某个子slice,下标必须合法
          func (v Value) Slice3(i,j,k) Value  //以Go1.3引入的3下标格式访问某个子slice,下标必须合法
          func (v Value) SetCap(i int)        //要求i必须在[v.Len(),v.Cap()]之间
          func (v Value) SetLen(i int)        //i必须在[0,v.Cap()]之间
          *映射类型
          func (v Value) Len() int
          func (v Value) IsNil() bool
          func (v Value) MapKeys() []Value//返回所有的键值
          func (v Value) MapIndex(key Value) Value
          func (v Value) SetMapIndex(key, x Value)//如果x是零值,那么表示删除一个元素
          func (v Value) Pointer() uintptr
          *指针类型   Go语言提供了两种指针类型,一种是通过*和其他类型复合而成,另一种是unsafe.Pointer
          func Elem() Type    值
          func(v Value) IsNil() bool
          func(v Value) Elem() Value
          func(v Value) Pointer() uintptr
          *数组
          func Elem() Type
          func Len() int
          func(v Value) Len() int
          func(v Value) Slice(i,j int) Value
          func(v Value) Slice3(i, j, k int) Value//这两个方法要求v.CanAddr()返回true
          *接口类型
          func(v Value) IsNil() bool//判断接口是否为空
          func(v Value) Elem() Value//返回接口包含的真实值
          func(v Value) InterfaceData() [2]uintptr//这个方法的用法比较奇怪,还未能找到一个合适的例子
          []byte类型
          func (v Value)Bytes() []bytes
          func (v Value)SetBytes(x []bytes)
          字符串类型
          func (v Value) SetString(x string)//设置字符串的值
          func (v Value) Index(i int)Value//访问单个字节
          func (v Value) Len() int//字符串的长度
    
  • Type

          Type
    
          func Size() uinptr          //大小: 一个该类型的值存储所需要的内存大小,以字节为单位
          func Name() string          //名称: 该类型在其定义包中的名称,有些类型没有名称(比如数组、slice、函数等等),返回一个空字符串
          func PkgPath() string           //定义位置: 该类型的定义位置,也就是导入该类型使用的import语句的参数。如果该类型是预定义的(string, error等)或者无名的,那么返回一个空字符串
          func Kind() Kind                //种类: 该类型所属的种类,reflect包定义了Kind类型来表示各种类型。重命名一个类型并不会改变其种类
          func NumMethod() int            //方法集: 该类型的方法集,Type类型提供了方法来返回方法数量,访问各个方法。reflect包定义了Method类型来表示一个方法
          func Method(index int) Method   //使用索引来访问方法集,索引从0开始,如果越界,将panic
          func MethodByName(name string) (Method, bool)//使用名称来访问某个方法,bool参数指示是否找到该方法
          func Implements( u Type) bool   //判断是否使用了接口u,u必须表示一个接口类型
          func ConvertibleTo(u Type) bool //是否可以使用标准转换语句,转换为其他类型
          func AssignableTo(u Type) bool  //是否可以赋值给其他类型的变量
          *函数类型
          func IsVariadic() bool//参数是否可变
          func NumIn() int        //参数的数量,需要注意的是,可变参数单独作为slice计算
          func NumOut() int       //返回值的数量,需要注意的是,可变参数单独作为slice计算
          func In(i int) Type     //第i个参数,i从0开始
          func Out(i int) Type    //第i个返回值,i从0开始
    
  • StructField

结构的字段具有很多特殊信息,定义了StructField类型来表示一个字段

        func NumField() int     //结构字段数量
        func Field(i int) StructField       //使用索引来访问字段,索引从0开始,如果越界将panic
        func FieldByName(name string) (StructField,bool)        //使用名称来访问字段,如果未找到那么返回false
        func FieldByNameFunc(match func(string) bool) (StructField,bool)        //访问名称使得match函数返回true的字段,在同一个内嵌层次上,只能有一个字段使得match返回true。如果同一层次上多个字段使得match返回true,
                                                                                那么这些字段都认为是不符合要求的
        func FieldByIndex(index []int) StructField      //这个方法使得访问结构的内嵌字段成为可能。将访问各个层次的字段的索引排列起来,就形成了一个[]int,参数index不可越界,否则panic             

        type StructField struct{
            Name string      //名称
            PkgPath string      //* 对于导出字段,为空字符串* 对于非导出字段,是定义该字段类型的包名
            Type        Type
            Tag         StructTag
            Offset uintptr     //在结构内的位移
            Index []int       //当使用Type.FieldByIndex()方法的参数
            Anonymous  bool        //是否为匿名字段
        }
  • StructTag 描述了结构字段的tag

      tag格式为:
      * 由多个部分连接而成,部分之间有可选的空格
      * 部分格式为 key:value
      * key是非空的字符串,由非控制字符组成,并且不可以是空格、双引号、冒号
      * 值由双引号包围,遵循Go字符串字面值语法
          
      func (tag StructTag) Get(key string) string     //将一个tag看做映射,各个部分就是映射的元素
    
  • Kind

reflect包使用Kind类型来表示类型所属的分类

推荐阅读更多精彩内容

  • 86.复合 Cases 共享相同代码块的多个switch 分支 分支可以合并, 写在分支后用逗号分开。如果任何模式...
    无沣阅读 800评论 1 5
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    萌萌的小伟哥阅读 728评论 0 9
  • 136.泛型 泛型代码让你可以写出灵活,可重用的函数和类型,它们可以使用任何类型,受你定义的需求的约束。你可以写出...
    无沣阅读 685评论 0 4
  • Generic codeenables you to write flexible, reusable funct...
    绿色庄园阅读 237评论 0 0
  • 前方是一个神奇的维度,是一个五彩的鲜花、大块的浮冰、跳跃的火种、黑暗的精灵共存的大树洞,一个用肉眼就能看到墨蓝结界...
    燚不语阅读 303评论 4 18