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?
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
}
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 (eg you could range
over it, check membership and ... in one line).
m := make(map[string]string)
...
m[split[0]] = strings.Join(split[1:], " ")
I ended up defining a method on my type and use an input to that method to return the attribute I wanted. Not ideal but it is straightforward and works well.
type PinMap struct {
Relay101 map[string]int `json:"192.168.1.101"`
Relay102 map[string]int `json:"192.168.1.102"`
}
// GetMap Allow dyanamic access of PinMap while maintaining struct
func (pm PinMap) GetMap(ip string) map[string]int {
switch ip {
case "192.168.1.101":
return pm.Relay101
case "192.168.1.102":
return pm.Relay102
default:
return pm.Relay101 // should probably throw and error
}
}
and then I used the code like this:
relayPinMap := pumps.pinMap.GetMap(relayID)
Pretty new to golang so please let me know if this is bad practice - will take down the answer if there is a good reason to.
Also note this felt hacky to me, but I needed it to work and I had to get it working in minutes😅. What I think would be better would be to make the type map[string]map[string]int
, ie use a map instead of a struct when you need dynamic access if you can.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.