Golang动态访问struct属性

时间:2017-12-24 14:05:17

标签: go struct

我正在golang中为json处理器编写一个快速的ssh配置。我有以下结论:

type SshConfig struct {
    Host string
    Port string
    User string
    LocalForward string
    ...
}

我正在循环遍历我的ssh配置文件的每一行,并在空格上拆分行并检查要更新的属性。

if split[0] == "Port" {
    sshConfig.Port = strings.Join(split[1:], " ")
}

有没有办法检查属性是否存在然后动态设置?

3 个答案:

答案 0 :(得分:3)

使用reflect包按名称设置字段:

// 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
}

这样称呼:

var config SshConfig

...

err := setField(&config, split[0], strings.Join(split[1:], " "))
if err != nil {
   // handle error
}

playground example

答案 1 :(得分:0)

您可以使用reflect包在运行时动态检查结构。请参阅docsblog

但是,如果您只想将文件读入结构,最好使用map[string]string之类的东西。在运行时检查地图要清晰得多(例如,您可以range检查地图,检查成员资格和......在一行中。)

m := make(map[string]string)
...
m[split[0]] = strings.Join(split[1:], " ")

答案 2 :(得分:0)

我最终在类型上定义了一个方法,并使用该方法的输入来返回我想要的属性。不太理想,但是简单明了,效果很好。

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
    }
}

然后我使用如下代码:

relayPinMap := pumps.pinMap.GetMap(relayID)

golang还是很陌生的,所以请让我知道这是否是不好的做法-如果有充分的理由会拒绝回答。

还请注意,这对我来说有点麻烦,但是我需要它来工作,而且我必须在几分钟内使其工作。我认为最好是将类型设为map[string]map[string]int,即,如果需要的话,在需要动态访问时使用映射而不是结构。