使用反射改变结构的通用解决方案

问题描述 投票:0回答:1

假设我有一个包含多个嵌套结构的结构:

type SomeInt int
type AnotherConfig struct {
    Value1 string
    Value2 int
    Value3 SomeInt
}
type SubConf struct {
    Value1 string
    Value2 int
    Conf   AnotherConfig
}
type Config struct {
    Value1 string
    Value2 int
    Conf   SubConf
}

我需要一个函数的实现,它将来自一些final标量场path作为输入,并在那里设置一个将自动转换为适当类型的值:

func (conf *Config) ChangeValue(path string, value string) {
    //Need implementation
}

func main() {
    conf := Config{}
    // Usage example:
    conf.ChangeValue("Conf.Conf.Value3", "123")
}

嵌套结构在开发过程中会不断变化,因此或多或少需要一个通用的解决方案。也许支持一组有限的类型转换,例如仅支持 stringsints,但它们可以被键入(如示例中所示)。

go reflection
1个回答
0
投票
func (conf *Config) ChangeValue(path string, value string) error {
    pathParts := strings.Split(path, ".")
    var f reflect.Value
    f = reflect.Indirect(reflect.ValueOf(conf))
    if f.Kind() != reflect.Struct {
        return errors.Errorf("expected struct %s given", f.Kind().String())
    }
    for _, key := range pathParts {
        f = f.FieldByName(key)
        if !f.IsValid() {
            return errors.Errorf("invalid path %s", path)
        }
    }

    if f.CanSet() {
        if f.Kind() == reflect.Int {
            intVal, err := strconv.ParseInt(value, 10, 64)
            if err != nil {
                return errors.Errorf("Value %s cannot be parsed as int (%s)", value, err.Error())
            }
            if !f.OverflowInt(intVal) {
                f.SetInt(intVal)
            }
        } else if f.Kind() == reflect.String {
            f.SetString(value)
        } else if f.Kind() == reflect.Bool {
            boolVal, err := strconv.ParseBool(value)
            if err != nil {
                return errors.Errorf("Value %s cannot be parsed as bool (%s)", value, err.Error())
            }
            f.SetBool(boolVal)
        } else {
            return errors.Errorf(
                "Wrong value or your path '%s' not indicates scalar type for %s",
                path, value,
            )
        }
    }
    return nil
}

© www.soinside.com 2019 - 2024. All rights reserved.