reflect?

起因在这:反射中CanInterface,CanAddress,CanSet的区别
golang1.13.1对应源码如下(不想康直接略过)

// CanInterface reports whether Interface can be used without panicking.
func (v Value) CanInterface() bool {
    if v.flag == 0 {
        panic(&ValueError{"reflect.Value.CanInterface", Invalid})
    }
    return v.flag&flagRO == 0
}

// CanAddr reports whether the value's address can be obtained with Addr.
// Such values are called addressable. A value is addressable if it is
// an element of a slice, an element of an addressable array,
// a field of an addressable struct, or the result of dereferencing a pointer.
// If CanAddr returns false, calling Addr will panic.
func (v Value) CanAddr() bool {
    return v.flag&flagAddr != 0
}

// CanSet reports whether the value of v can be changed.
// A Value can be changed only if it is addressable and was not
// obtained by the use of unexported struct fields.
// If CanSet returns false, calling Set or any type-specific
// setter (e.g., SetBool, SetInt) will panic.
func (v Value) CanSet() bool {
    return v.flag&(flagAddr|flagRO) == flagAddr
}
三个函数都和v.flag有关,flag定义如下
type flag uintptr
flag的生成过程如下:
// func unpackEface(i interface{}) Value
f := flag(t.Kind())   //给flag添加类型字段(0-4位)
if ifaceIndir(t) {
    f |= flagIndir // flagIndir=1 << 7     第7位置1
}
// func (t *rtype) Kind() Kind
return Kind(t.kind & kindMask)  
// const define
type Kind uint
// func ifaceIndir(t *rtype) bool
return t.kind&kindDirectIface == 0 
源码可见采用了bit map(32bit),各个位作用如下:
标志名 Kind Mask Sticky RO Embed RO Indir Addr Method MethodNum
1<<flagKindWidth - 1 1 << 5 1 << 6 1 << 7 1 << 8 1 << 9 flag<<MethodShift
位置 第0-4位 第5位 第6位 第7位 第8位 第9位 第10-31位(共22位 注释给出的是23+)
注释 five bits give the Kind of the value obtained via unexported not embedded field, so read-only obtained via unexported embedded field, so read-only val holds a pointer to the data v.CanAddr is true (implies flagIndir) v is a method value,If flag.kind() != Func, code can assume that flagMethod is unset a method number for method values
用处 类型值 粘性只读?通过私有未嵌入变量获取 嵌入只读?通过非私有未嵌入变量获取Field() will clear flagEmbedRO 指针类型? 当使用ptr.Elem()或slice.Index()时置位 是否为函数类型,即Kind == 19(reflect.Func) 方法数,函数类型方法数为0

flagStickyRO|flagIndir|flagAddr 额外有:
当调用 func (v Value) Field(i int) Value 时:

//返回的Value Inherit permission bits from v, but clear flagEmbedRO.
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
if !field.name.isExported() {
        if field.embedded() {
            fl |= flagEmbedRO
        } else {
            fl |= flagStickyRO
        }
    }

其余参数定义如下:

- Kind Width Method Shift RO
5 10 flagStickyRO | flagEmbedRO
解释 种类数量共27个,五位bit可容纳2^5=32个类型 MethodNum=flag>>10 变量只读
用处 表明类型占用bit数 MethodNum变量偏移量 ReadOnly只读, 当非RO时才可转换为Interface()

结论

CanInterface

满足条件: not flag.RO即可读写
相当于满足条件:not flagStickyRO or not flagEmbedRO
flagStickyRO: 初步猜测是普通公有成员
flagEmbedRO: 初步猜测是匿名成员
若有老哥明白,希望帮忙纠正一下

已知:结构体内私有变量 CanInterface == false

CanAddress

满足条件:有指针变量t即TypeOf(t).Kind() == ptrv = ValueOf(t).Elem() 此时v是CanAddress
通常理解是传地址给ValueOf并且使用Elem()取值

CanSet

满足条件: not flag.RO and flag.Addr
相当于满足条件:CanInterface and CanAddress
通常理解是可读写可寻址

关于rtype: sync with ../runtime/type.go:/^type._type.

更底层了,待续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 基础类型描述 Type Kindtype Kind uint 基础类型常量const ( Invalid K...
    copyLeft阅读 5,745评论 0 0
  • 接口的定义 接口提供了一种方式来说明对象的行为,它是一个方法集,是这些方法不包含(实现)代码:它们没有被实现(它们...
    lixin_karl阅读 3,725评论 0 3
  • 编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机...
    豆瓣奶茶阅读 14,347评论 0 32
  • [TOC] Golang的反射reflect深入理解和示例 【记录于2018年2月】 编程语言中反射的概念 在计算...
    AllenWu阅读 4,292评论 1 14
  • 前言 反射 —— 如果你之前学过一些别的语言,比如java可能就会了解,反射是一个传说中很厉害的操作,算是一个高级...
    LinkinStar阅读 4,402评论 0 0