假设我有一个包含多个嵌套结构的结构:
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")
}
嵌套结构在开发过程中会不断变化,因此或多或少需要一个通用的解决方案。也许支持一组有限的类型转换,例如仅支持 strings 和 ints,但它们可以被键入(如示例中所示)。
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
}