Reputation: 1015
I am writing a quick ssh config to json processor in golang. I have the following stuct:
type SshConfig struct {
Host string
Port string
User string
LocalForward string
...
}
I am currently looping over every line of my ssh config file and splitting the line on spaces and checking which property to update.
if split[0] == "Port" {
sshConfig.Port = strings.Join(split[1:], " ")
}
Is there a way to check a property exists and then set it dynamically?
Upvotes: 14
Views: 13896
Reputation: 6537
You could use reflect package to dynamically inspect structs at runtime. See docs and blog.
But if all you want to do is read the file into a structure its better to use something like map[string]string
. Inspecting maps at runtime is much cleaner (e.g. you could range
over it, check membership and ... in one line).
m := make(map[string]string)
...
m[split[0]] = strings.Join(split[1:], " ")
Upvotes: 1
Reputation: 120931
Use the reflect package to set a field by name:
// setField sets field of v with given name to given value.
func setField(v interface{}, name string, value string) error {
// v must be a pointer to a struct
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Struct {
return errors.New("v must be pointer to struct")
}
// Dereference pointer
rv = rv.Elem()
// Lookup field by name
fv := rv.FieldByName(name)
if !fv.IsValid() {
return fmt.Errorf("not a field name: %s", name)
}
// Field must be exported
if !fv.CanSet() {
return fmt.Errorf("cannot set field %s", name)
}
// We expect a string field
if fv.Kind() != reflect.String {
return fmt.Errorf("%s is not a string field", name)
}
// Set the value
fv.SetString(value)
return nil
}
Call it like this:
var config SshConfig
...
err := setField(&config, split[0], strings.Join(split[1:], " "))
if err != nil {
// handle error
}
Upvotes: 17