使用反射

时间:2015-10-14 22:25:30

标签: reflection go

我有这种地图 type Store map[string]string

从这张地图中,我想填写一个结构。目标是,对于结构的每个字段,找到与字段名称匹配的键,获取值,并根据struct字段的类型,将值转换为正确的struct字段类型并进行设置。

基本上地图将包含整数,布尔值,字符串和持续时间作为字符串,因此convestion应该只是strconv.atoi()time.parseDuration() ......

另外,我想使用structs标签来指定地图中键的名称,因为struct字段可能是camelCase,而地图中的键将是这样的" example_key&#34 ;

知道如何做到这一点。我读过关于golang反射但它对我来说仍然是不透明的。我只需要解释来解决问题,然后我想我可以自己处理实现。

由于

1 个答案:

答案 0 :(得分:4)

为了避免在评论中进行一些扩展讨论,我只是回答一下我将选择的两种方法。一般来说,我会避免使用反射方法。有些情况下需要它,但大多数情况下,更冗长,文字,简单的代码会更好,即使它有更多的行,并且方法之间存在一些重叠。

所以,从简单的例子开始。假设您有3种类型,GroceryStoreComputerStoreCornerStore。在定义每个类型的任何包中,定义一些类似于方法的构造函数是相当普遍的(它们不是技术上的构造函数,只是实例化类型并返回它但具有相同目的的包作用域方法)。所以一个例子就是;

func NewComputerStore(store Store) *ComputerStore {
      return &ComputerStore{
            Name: store["Name"],
            Location: store["Location"],
            //ect
      }
}

当然上面的例子完全不安全。实际上,您需要使用v, ok := myMape["key"]语法,然后分配if ok并执行任何操作(可能是分配默认值,日志错误和抛出错误的某种组合)。

现在,如果你想要一个通用的方法...它通常看起来更像这样(注意这是未测试的,并且比工作示例更多的伪代码);

func (s *Store) ConvertToObject(obj interface{}) error {
    val := reflect.ValueOf(obj)
    for i := 0; i < val.NumField(); i++ {
        switch v := val.Field(i).(type) {
        case int64:
            val.Field(i).SetInt(strconv.Atoi(s[val.Field(i).Name]))
        }
    }
}

所以上面代码的基本思想就是这个。您是从商店地图开始的。调用者知道该映射应该是什么类型。他们调用此方法传递该类型的新实例。在这种方法中,我们并不关心类型是什么,我们关心它的类型是什么。所以我迭代传入的对象上的所有字段。每个字段都通过类型开关(因为我需要一个字符串到X转换,对于此方法应该使用的结构中存在的每种类型,或者在至少是一个不错的基础案例),对于每种类型,您可以使用字段名称进行分配,以在Store地图中查找其值并从字符串转换为X.

希望这是有道理的。如果它没有真正澄清这种方法,我可以跟进。请记住,上面的代码并不打算运行。此外,我已经忽略了所有错误处理,你需要很多才能使广义功能发挥作用(如果转换失败该怎么办?如果类型不被识别怎么办?怎么样?所有其他可能不常见的错误?)。