2

Using Go's reflect package, is there a way to set a pointer in a struct if the pointer is nil? Looking at the reflect package, if reflect.Value.CanSet() is false then any Set() calls will yield a panic. Is there another way around this, only using the reflect package, not depending on any direct reference to the struct? For example, how can I set the empty last name as "Johnson" in the code below?

package main

import (
    "fmt"
    "reflect"
)

type Person struct {
    FirstName *string
    LastName  *string
}

func main() {
    p := Person{}
    firstName := "Ryan"
    p.FirstName = &firstName

    rp := reflect.ValueOf(p)
    fmt.Println("rp:", rp)

    for i := 0; i < rp.NumField(); i++ {
        fmt.Printf("%s: Pointer: %d CanSet: %t\n", rp.Type().Field(i).Name, rp.Field(i).Pointer(), rp.Field(i).Elem().CanSet())
    }

    rp.Field(0).Elem().SetString("Brian")
    fmt.Println(*p.FirstName)

    // Yields nil pointer error
    // rp.Field(1).Elem().SetString("Johnson")
    // fmt.Println(*p.LastName)

    fmt.Println(rp.Field(1).Type()) 
    fmt.Println(rp.Field(1).CanSet())
    // fmt.Println(rp.Field(1).Elem().Type()) // nil pointer here also
    fmt.Println(rp.Field(1).Elem().CanSet())
}

See in Golang Playground

2
  • I'll ask the obvious question here... why would you want to do this? I myself have never seen much of a reason to use pointers to strings, nor have I seen them used in the standard libraries. Commented May 2, 2017 at 18:03
  • 1
    Fair question. When I expose a REST API, its my way of knowing if the client provided a field or not. If they were not pointers, the empty value of a string is "". Then I'd have to ask.. did the client provide "" or did they provide nothing? Plus, I'm adding unique tags to the struct fields like.. Validate and Transform. So, I'm using the reflect package there to parse those. Commented May 2, 2017 at 18:07

1 Answer 1

11

You first need a pointer to a Person{}, because you need to set a value to the LastName Field.

p := &Person{}

Then you can set a valid pointer value to the LastName field, which will allow you to set the string value:

rp.Field(1).Set(reflect.New(rp.Field(1).Type().Elem()))
rp.Field(1).Elem().SetString("Jones")

https://play.golang.org/p/f5MjpkDI2H

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

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.