Good afternoon, I try to deal with reflection and tags in the structures in Go, using the configuration example for the application.

There is a code:

package main import ( "fmt" "os" "reflect" "flag" ) type AppConfig struct { Pg string `cli:"pg" env:"PG" default:"host=host.local dbname=db user=user password=password" description:"Connection to PostgreSQL"` Redis string `cli:"redis" env:"REDIS" default:"host.local" description:"Redis server"` } func main() { config := GetConfig(&AppConfig{}) fmt.Println(config) } func GetConfig(config *AppConfig) *AppConfig { ref := reflect.TypeOf(*config) value := reflect.ValueOf(*config) for i := 0; i < value.NumField(); i++ { field := ref.Field(i) name := field.Tag.Get("env") if name != "" { env := os.Getenv(name) if env != "" { value.Field(i).SetString(env) } else { def := field.Tag.Get("default") if def != "" { value.Field(i).SetString(def) } } } /* cli := field.Tag.Get("cli") if cli != "" { flag.StringVar((*string)(value.Field(i).Pointer()), cli, value.Field(i).String(), field.Tag.Get("description")) } */ } flag.Parse() return config } 

Sandbox: https://play.golang.org/p/b7bDUd-mj- I get

 panic: reflect: reflect.Value.SetString using unaddressable value 

I feel that something is missing, but what?

PS In the commented section, work with command-line flags, but here my understanding of what is happening there is not enough

1 answer 1

Your problem is here:

 value := reflect.ValueOf(*config) 

Because you rename a pointer, you get the value of AppConfig . It can not be changed. Why? Because in essence you are doing this:

 func setX(x int) { x = 2 } 

That is, refer by value, not by reference. Such a function will not change the original x . However, this will change:

 func setX(x *int) { *x = 2 } 

You need to do in your function

 value := reflect.ValueOf(config) 

and then go to value.Elem() . Playground: https://play.golang.org/p/ZKCsS-82v- .

See also Third Law of Reflection .

  • Thank you very much for the answer. I wanted to clarify one more question about reflection: can you not get to private fields (which are small)? - chernomyrdin
  • Not private, but unexported. And yes, you can not install them. See the CanSet dock. - Ainar-G
  • Yes, thanks for the clarification, while I am confused about the wording :-) - chernomyrdin
  • @chernomyrdin This is not for comments. If you do not master, write a new question with a specific example, what you have and what you need to do. - Ainar-G