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
}