Southclaws
Southclaws

Reputation: 1940

Set the value of a struct field with reflection when the field is a pointer-to-x

I have a struct of pointers to various primitives. The struct is a config for an application and the reason the fields are pointers is so I can determine between a field set to the default and a field that hasn't been set at all - to enforce "required" fields.

Here is a simple example:

type Config struct {
    A *string
    B *int
    C *bool
    D *[]string // wildcard!
}

So I grab the reflect.Value via reflect.ValueOf(*cfg) which gives me a .Field on each element, which I iterate through.

The thing is, each element doesn't pass CanAddr or CanSet, I can't seem to find a way to set the value held behind the pointer. Is this a limitation of the language? Will I need to make my fields non-pointers? That would suck as there would be no way to determine if a user specified an empty string or just didn't set it at all for example.

Oh and bonus points for setting/appending a []string field! That one confused me even without pointers thrown in the mix!

Upvotes: 0

Views: 3881

Answers (1)

Thundercat
Thundercat

Reputation: 121129

Replace these lines:

t := reflect.TypeOf(*cfg)
v := reflect.ValueOf(*cfg)

with

v := reflect.ValueOf(cfg).Elem()
t := v.Type()

to get an addressable value.

The value created by reflect.ValueOf(*cfg) has no reference to addressable memory. The fix is to dereference the pointer in the reflect domain.

Regarding the []string. Because there's a difference between a null slice and an empty slice, there may be no need to use *[]string. In any case, use the reflect.Append function to append to a slice:

var s []string
v := reflect.ValueOf(&s).Elem()
v.Set(reflect.Append(v, reflect.ValueOf("hello")))
v.Set(reflect.Append(v, reflect.ValueOf("world")))
fmt.Println(s) // prints [hello world]

Upvotes: 2

Related Questions