0

My goal is to take a nil pointer to a struct (but could be any type), passed as an interface{}, and initialize a struct in its place.

My test code (playground link) is:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    Foo string
}

func main() {
    var x *Foo
    var y interface{} = x
    fmt.Printf("Before: %#v\n", y)
    fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))

    rv := reflect.ValueOf(y)
    rv.Set(reflect.New(rv.Type().Elem()))

    fmt.Printf("After: %#v\n", y)
}

I hope the code is self-documenting. But the goal is essentially to convert y which begins as an uninitialized pointer to Foo, ((*main.Foo)(nil)) into a pointer to an initialized (zero-value) instance ofFoo: &main.Foo{Foo:""}. But I'm getting reflect.Value.Set using unaddressable value. I don't understand why the value I'm attempting to set is unaddressable. I've spent the day reading through the source code to the standard library JSON unmarshaler, and other SO posts, but am still clearly overlooking something.

If I peel away the outer interface{}:

rv := reflect.ValueOf(y).Elem() // Remove the outer interface{}
rv.Set(reflect.New(rv.Type().Elem()))

the error becomes reflect: call of reflect.Value.Type on zero Value.

4
  • Using a loop implies that there may be arbitrarily many layers, but there are only three: the interface type of the variable, the pointer to the value, and the value itself. Commented Jul 12, 2017 at 15:34
  • @Adrian: In production,there may be an arbitrary number of layers. But here, clearly there aren't. I've removed the loop. Commented Jul 12, 2017 at 15:35
  • How would you end up with an arbitrary number of layers? Commented Jul 12, 2017 at 15:37
  • @Adrian: SomeUnmarshalWrapper(&result) followed by func SomeUnmarshalWrapper(i interface{}) { json.Unmarshal(&i) ... or similar. Commented Jul 12, 2017 at 15:41

3 Answers 3

4

Try this:

var x *Foo
var y interface{} = x
fmt.Printf("Before: %#v\n", y)
fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))

// Must take address of y to set it. Dereference with Elem() to get value for y
rv := reflect.ValueOf(&y).Elem()

// Interface element type is *main.Foo, dereference with Elem() to get main.Foo
t := rv.Elem().Type().Elem()
rv.Set(reflect.New(t))
fmt.Printf("After: %#v\n", y)

playground example

You can also assign y instead of setting it via reflection:

var x *Foo
var y interface{} = x
fmt.Printf("Before: %#v\n", y)
fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))
rv := reflect.ValueOf(y)
t := rv.Type().Elem()
y = reflect.New(t).Interface()
fmt.Printf("After: %#v\n", y)

playground example

Sign up to request clarification or add additional context in comments.

3 Comments

I second this answer. Learned something new :)
Would there be a way to set x through y? Because x is still (*Foo)(nil).
Already found out. You need to pass a pointer to the pointer. I asked my question here and it was answered. In case anyone ever wonders.
1

Without knowing your actual use case, it's hard to say what solution you require, however this works for your example:

var x *Foo
var y interface{} = x
rv := reflect.ValueOf(y)
y = reflect.New(rv.Type().Elem()).Interface()

Comments

1

In your example rv.CanAddr() is false and consequently you cannot set it (rv.CanSet() is false).

Problem: if you have a pointer to nil it is not addressable. A pointer to a pointer to nil (or a pointer to an interface) however is addressable.

You can get your example to work in different ways:

  • initialize x to be non-nil (probably not the point here)
  • set y to a new Value with reflect.New(..)

    func main() {
        var x *Foo
        var y interface{} = x
        fmt.Printf("Before: %#v\n", y)
        fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))
    
        rv := reflect.ValueOf(y)
        y = reflect.New(rv.Type().Elem()).Interface()
    
        fmt.Printf("After: %#v\n", y)
    }
    

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.