go reflect: how to dynamically create a pointer to a pointer to ...? - go

I would like to create a reflect.Value that represents a multiple-level nested pointer to a final value. The nesting level is not known at compile time. How can I create pointers to pointers using reflect?
I already stumble at the "unaddressable value" hurdle when trying to create a pointer to a pointer.
dave := "It's full of stars!"
stargazer := reflect.ValueOf(&dave)
stargazer = stargazer.Addr() // panic: reflect.Value.Addr of unaddressable value
Same for stargazer.UnsafeAddr(), etc. While stargazer.Elem().UnsafeAddr() etc. works, I can't see how this helps in (recursively) creating a new non-zero pointer to a pointer...

Use the following code to create a pointer to the value in stargazer.
p := reflect.New(stargazer.Type())
p.Elem().Set(stargazer)
// p.Interface() is a pointer to the value stargazer.Interface()
Example:
dave := "It's full of stars!"
stargazer := reflect.ValueOf(dave)
for i := 0; i < 10; i++ {
p := reflect.New(stargazer.Type())
p.Elem().Set(stargazer)
stargazer = p
}
fmt.Printf("%T\n", stargazer.Interface()) // prints **********string

Related

Golang fill slice in function not working

I am trying to add stuff to my slice but somehow the slice is never updated.
endpointsList := make([]string, 3)
for _, route := range routes {
if len(route.Endpoints) > 0 {
waitGroup.Add(1)
go endpointRoutine(route, template, route.Protected, &waitGroup, &endpointsList)
}
}
I pass the endpointsList by reference, meaning I should be able to assign new things to its memory location I think.
In the function endpointRoutine I do this:
list := make([]string, 3)
for _, r := range route.Endpoints {
list = append(list, "some data comes here...")
}
endpointsList = &list
When I do a printr after this (below my first bit of code and AFTER the waitGroup.Wait() part) the slice is still empty.
Obviously, I am overwriting the slice now and my final goal is to ADD to the slice. But when I try to add with this code:
endpointsList = append(endpointsList, "fdssdfsdfsdf")
It gives me the error:
cannot use endpointsList (type *[]string) as []Type
Can someone please explain to me what might be wrong?
With endpointsList = &list, you are assigning the pointer pointing to the slice to some other slice. To set the slice, do this instead:
*endpointsList=list

How to Make array of elements with type specified at run time

I am trying to create a array of elements with a type known only at the run time (a pkg API gets to retrieve elements in json and convert to struct). I have a helper function something like below, which takes an interface as a param and trying to get the type of interface while calling make.
golang compiler doesn't seems to like it.
var whatAmI = func(i interface{}) {
a := reflect.TypeOf(i)
//var typ reflect.Type = a
b := make (a, 10) //10 elem with type of i
//b := new (typ)
fmt.Printf ("a: %v b: %v", a, b)
}
prog.go:21:14: a is not a type
I tried various combinations of reflects but no help so far.
This seems to me can be a common problem to run in to. How can I solve/workaround this?
Get the type for a slice given a value of the element type, v:
sliceType := reflect.SliceOf(reflect.TypeOf(v))
Create a slice with length and capacity (both 10 here).
slice:= reflect.MakeSlice(sliceType, 10, 10)
Depending on what you are doing, you may want to get the actual slice value by calling Interface() on the reflect.Value:
s := slice.Interface()
Run it on the playground.
Just make like :
b := make([]interface{}, 10)
for i := range b {
b[i] = reflect.Zero(a)
}

get underlying type from a specific interface in golang

As the example, can I get a zero value of its underlying type from the interface Work?
func MakeSomething(w Worker){
w.Work()
//can I get a zeor value type of The type underlying w?
//I tried as followed, but failed
copy :=w
v := reflect.ValueOf(&copy)
fm :=v.Elem()
modified :=reflect.Zero(fm.Type())//fm.type is Worker, and modified comes to be nil
fm.Set(modified)
fmt.Println(copy)
}
type Worker interface {
Work()
}
the playground
Since w contains a pointer to a Worker, you might want to get a zero value of the element it is pointing to. Once you get the element, you can create a zero value of its type:
v := reflect.ValueOf(w).Elem() // Get the element pointed to
zero := reflect.Zero(v.Type()) // Create the zero value
Above code snippet will panic if you pass in a non-pointer to MakeSomething. To prevent this, you might want to do the following instead:
v := reflect.ValueOf(w)
if reflect.TypeOf(w).Kind() == reflect.Ptr {
v = v.Elem()
}
zero := reflect.Zero(v.Type())
If you actually want to have a pointer to a new Worker, you just replace reflect.Zero(v.Type()) with reflect.New(v.Type()).

Golang: How to change struct field value in slice of interfaces

Problem in Playground: https://play.golang.org/p/UKB8f4qGsM
I have a slice of interfaces, I know for sure which type they have (in reality i don't so I'd have to type switch it, but I left that out for clarity). How can I assign a value to a field in the struct behind the interface? The type assertion seems to take away the reference.
I also tried using pointers, that too doesn't work though, mostly because I can't type assert then (type *inter cannot be type asserted) and when I dereference it, it kinda makes it pointless to even have...
I'm not that experienced in Go, I would appreciate every help I can get.
You can't change the value stored in the interface, you need to use a pointer to the value you want to change:
for i := 0; i < 5; i++ {
slice = append(slice, &b{a: a{name: "Tom"}})
}
for i, _ := range slice {
x := slice[i].(*b)
x.name = "Tim"
}

Pointer to loop variable for range over map or slice of interface{}

I'm using go-hdf5 and I'm hitting a problem when trying to write attributes in a loop from a map.
The attributes are created correctly (correct name and datatype) but the written value is garbage.
The same code outside of the loop works fine. I tried both the v := v idiom and wrapping the code in a closure to capture v but it doesn't make a difference.
Here is the gist of the code (error checking intentionally left out for clarity):
m := map[string]interface{"foo", 42}
for k, v := range m {
// [...]
v := v
attr.Write(&v, dtype)
}
The Write method is using reflection to grab a pointer to the value and forwards it to the C library. The relevant part of the code is just:
func (s *Attribute) Write(data interface{}, dtype *Datatype) error {
v := reflect.ValueOf(data)
addr := unsafe.Pointer(v.Pointer())
return h5err(C.H5Awrite(s.id, dtype.id, addr))
}
If I replace the map by a slice of interface{}, I get the exact same problem so my hunch is that this has to do with the binding of loop variables, but yet v := v doesn't help so I'm not sure.
I'm quite familiar with Go, HDF5 (C library) and go-hdf5 but I'm really stuck here. Any idea?
BTW I'm using go1.5.1 darwin/amd64.
The Write method needs a pointer to a value, not a pointer to an interface containing the value. You can get it using reflection:
u := reflect.New(reflect.ValueOf(v).Type())
u.Elem().Set(reflect.ValueOf(v))
v := u.Interface()

Resources