Home > other >  Golang: Get the pointer to a struct using reflection
Golang: Get the pointer to a struct using reflection

Time:03-26

I'm trying to write code that recursively traverses a struct and keeps track of pointers to all its fields to do basic analysis (size, number of references, etc). However, I'm running into an issue where I can't seem to get reflection to give me the pointer to a pure struct. I have the following code as an example:

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
}

If I wanted to traverse fooObj, that would be fine until I entered barObj at which point I again encounter fooObj. Because I don't have a way to get the pointer for the initial fooObj encounter, I end up traversing fooObj twice until I hit barObj the second time and exit the recursion. Any idea how to get a struct's pointer using reflection?

CodePudding user response:

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 returns a pointer value representing the address of v. It panics if CanAddr() returns false. Addr is typically used to obtain a pointer to a struct field or slice element in order to call a method that requires a pointer receiver.

CodePudding user response:

This takes a pointer of a value if it's possible.

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
}
  • Related