Reflection.Pointer()返回的值不是值地址

时间:2018-11-05 12:08:19

标签: pointers go struct reflection

type BookInfo struct {
    Meta         *TableMeta
    ...
}

func (si *schemaInfo) getTabInfo(obj interface{}) (*tabInfo, error) {
    typ := reflect.TypeOf(obj)
    val := reflect.ValueOf(obj)
    if typ.Kind() != reflect.Ptr {
        return nil, errors.New("nborm.schemaInfo.getDBInfo() error: required a pointer")
    }
    meta := *(**TableMeta)(unsafe.Pointer(val.Pointer()))
    ...
 }

getTabInfo()运作良好,但是我想知道为什么val.Pointer()返回值**TableMeta?为什么不使用*TableMetareflect的文档说

  

指针将v的值作为uintptr返回。它返回uintptr而不是   不安全的指针,以便使用反射的代码无法获得   不安全的指针,而不显式导入不安全的程序包。它   如果v的种类不是Chan,Func,Map,Ptr,Slice或   UnsafePointer。

在我的脑海中:

info := &BookInfo{}
val := reflect.ValueOf(info)
ptr := val.Pointer()
meta := (*TableMeta)(unsafe.Pointer(val.Pointer()))

应该可以,但是实际上当我调用val.Pointer()时,返回的值是*TableMeta**TableMeta)的指针。

1 个答案:

答案 0 :(得分:1)

您拥有的值是指向BookInfo结构的指针,其类型为*BookInfo。并且BookInfo.Meta字段的类型也是一个指针,它的类型为*TableMeta,因此*BookInfo可以看作**TableMeta,因此是“双”指针

的确,struct指针指向其第一个字段,但不要在其上建立。很脆弱。如果在字段之前添加字段,则字段将严重损坏(仅在运行时发生,由于软件包unsafe而没有编译时消息)。

因此,如果值的类型为*BookInfo,只需从reflect.Value包装器中获取该值,就可以像value.Meta那样引用其字段,其类型为{{ 1}}。避免使用软件包*TableMeta,尤其是在不需要它的情况下。