为了账号安全,请及时绑定邮箱和手机立即绑定

Golang:使用反射获取指向结构的指针

Golang:使用反射获取指向结构的指针

Go
收到一只叮咚 2022-11-23 20:09:31

我正在尝试编写递归遍历结构并跟踪指向其所有字段的指针以进行基本分析(大小、引用数量等)的代码。但是,我遇到了一个问题,我似乎无法得到反射来给我指向纯结构的指针。我以下面的代码为例:


type foo struct {

    A    *bar

    data []int8

}


type bar struct {

    B       *foo

    ptrData *[]float64

}


func main() {

    dataLen := 32

    refData := make([]float64, dataLen)


    fooObj := foo{data: make([]int8, dataLen)}

    barObj := bar{

        B:       &fooObj,

        ptrData: &refData,

    }

    fooObj.A = &barObj


    fooVal := reflect.ValueOf(fooObj)

    _ := fooVal.Addr().Pointer() // fails

    _ := fooVal.Pointer() // fails


    // More analysis code after this

}

如果我想穿越fooObj,那就好了,直到我进入barObj,然后我又遇到了fooObj。因为第一次fooObj遇到的指针没办法拿到,最后遍历fooObj了两次,直到碰到barObj第二次才退出递归。知道如何使用反射获取结构的指针吗?


查看完整描述

3 回答

?
一只斗牛犬

TA贡献1520条经验 获得超2个赞

package main


import (

    "reflect"

    "fmt"

)


type foo struct {

    A    *bar

    data []int8

}


type bar struct {

    B       *foo

    ptrData *[]float64

}


func main() {

    dataLen := 32

    refData := make([]float64, dataLen)

    

    // allocate here, now value has a pointer

    fooObj := &foo{data: make([]int8, dataLen)} 

    barObj := bar{

        B:       fooObj,

        ptrData: &refData,

    }

    fooObj.A = &barObj


    fooVal := reflect.ValueOf(fooObj)

    fmt.Println(fooVal.Pointer()) // succeeds


    // More analysis code after this

}

Addr 返回一个指针值,表示 v 的地址。如果 CanAddr() 返回 false,它会崩溃。Addr 通常用于获取指向结构字段或切片元素的指针,以便调用需要指针接收器的方法。


查看完整回答
反对 回复 2022-11-23
?
开满天机

TA贡献1526条经验 获得超12个赞

如果可能的话,这需要一个值的指针。


package main


import "reflect"

import "fmt"


func main() {

    val := new(int)

    slice := []int{}

    local := 10

    fn := func() {}


    fmt.Println(PointerOf(val))

    fmt.Println(PointerOf(slice))

    fmt.Println(PointerOf(&local))

    fmt.Println(PointerOf(fn))

    fmt.Println(PointerOf(3))

}


func PointerOf(value any) (p uintptr, ok bool) {

    rValue := reflect.ValueOf(value)

    

    if(rValue.Kind() == reflect.Pointer || rValue.Kind() == reflect.Slice || rValue.Kind() == reflect.Func) {

        return rValue.Pointer(), true

    }    


    if(rValue.CanAddr()) {

        return rValue.Addr().Pointer(), true

    }


    return

}


查看完整回答
反对 回复 2022-11-23
?
holdtom

TA贡献1516条经验 获得超10个赞

正如您所提到的,您的代码在这部分失败了


fooVal := reflect.ValueOf(fooObj)

_ = fooVal.Addr().Pointer() // fails

_ = fooVal.Pointer() // fails

In foostructdata不是指针值。


type foo struct {

    A    *bar

    data []int8

}

您正在尝试在非指针类型上调用reflect.Value.Addr().Pointer()and ,从而导致错误。reflect.Value.Pointer()


您可以通过检查类型是否实际上是来防止这种情况ptr


package main


import (

    "reflect"

)


type foo struct {

    A    *bar

    data []int8

}


type bar struct {

    B       *foo

    ptrData *[]float64

}


func main() {

    dataLen := 32

    refData := make([]float64, dataLen)


    fooObj := foo{data: make([]int8, dataLen)}

    barObj := bar{

        B:       &fooObj,

        ptrData: &refData,

    }

    fooObj.A = &barObj


    fooVal := reflect.ValueOf(fooObj)


    if fooVal.Kind().String() == "ptr" {

        _ = fooVal.Addr().Pointer() // ok

        _ = fooVal.Pointer()        // ok


       // More analysis code for pointer types

    } else {

       // More analysis code for non-pointer types

    }

}


查看完整回答
反对 回复 2022-11-23

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信