Reflection 用反射填充贴图中的结构

Reflection 用反射填充贴图中的结构,reflection,go,Reflection,Go,我有一张这种地图 键入商店地图[字符串]字符串 从这张地图上,我想填充一个结构。目标是,对于结构的每个字段,找到与字段名匹配的键,获取值,并根据结构字段的类型,将值转换为适当的结构字段类型并进行设置 基本上,映射将包含整数、布尔值、字符串和持续时间作为字符串,因此对流应该是简单的strconv.atoi(),time.parseDuration() 另外,我想使用structs标记来指定映射中键的名称,因为struct字段可能是camelCase,而映射中的键类似于“example_key” 你

我有一张这种地图
键入商店地图[字符串]字符串

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

基本上,映射将包含整数、布尔值、字符串和持续时间作为字符串,因此对流应该是简单的
strconv.atoi()
time.parseDuration()

另外,我想使用structs标记来指定映射中键的名称,因为struct字段可能是camelCase,而映射中的键类似于“example_key”

你知道怎么做吗。我读过关于golang reflection的文章,但对我来说,它仍然是不透明的。我只需要一个解释来解决这个问题,然后我认为我可以自己处理实现


谢谢

为了避免在评论中进行长时间的讨论,我将给出一个答案,解释我将选择的两种方法。一般来说,我会避免使用反思法。有些情况下会调用它,但大多数情况下,更详细、更文字化、更简单的代码会更好,即使它多了几行,并且方法之间有一些重叠

所以,从简单的例子开始。假设您有3种类型,
GroceryStore
ComputerStore
,和
CornerStore
。在定义每个类型的任何包中,定义一些类似构造函数的方法(它们不是技术上的构造函数,只是实例化类型并返回类型但用途相同的包作用域方法)是相当常见的。举个例子

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接口{})错误{
val:=反射值(obj)
对于i:=0;i
以上代码的基本思想是这样的。你从一张商店地图开始。调用方知道映射应该是什么类型。他们调用此方法传递该类型的新实例。在这个方法中,我们并不真正关心它的类型,我们关心它的字段的类型。因此,我迭代传入的对象上的所有字段。每个字段都通过类型开关进行转换(因为我需要对结构中存在的每个类型进行字符串到X的转换,这个方法应该使用,或者至少是一个合适的基本情况),对于每种类型,您可以使用字段名在
存储
映射中查找其值并从字符串转换为X来进行赋值


希望这是有道理的。如果它没有真正阐明方法,我可以跟进。请记住,上面的代码不是用来运行的。此外,我还忽略了使通用函数工作所需的所有错误处理(如果转换失败怎么办?如果类型无法识别怎么办?所有其他不常见的可能错误怎么办?)。

这是一种适用于一般情况的方法吗?否则,约定是在包中定义一个构造函数,在其中执行赋值并返回一个新实例。它类似于
func NewStoreObject(store map[string]string)StoreObject,错误
。如果你在寻找一个广义的解决方案,你会问很多问题。但我想我也可以解释一下。它只是反映结构上的类型,根据字段名对映射进行索引,打开结构字段类型,在每种情况下都有代码进行转换和赋值。@evanmcdonnal您好!这不是针对一般用例,而是针对特定用例。我现在将确切地说明结构中使用了哪些类型,因此我只对这些类型进行转换,但我仍然需要测试reflect.Type,我猜。地图不会作为参数传递,它来自其他地方,但你建议的原型是我所想的。嗯,这两种范式都不适合。如果您使用的是反射,我希望您使用它来决定在运行时在哪些字段上设置哪些值。如果您编写的代码在编译时显示为
thisType.Name=storeMap[“Name”]
,那么您也可以使用我描述的构造函数类型范例,因为每种类型都有一个特例,就像它们都有自己的构造函数方法接收映射并返回实例一样。如果你想要一个像
ConvertoObject(store-store)interface{}
这样的单一方法,那么使用反射是合理的。@evanmdonnal我理解你的观点。我认为这比写一个大的构造函数块要“干净”得多。你能不能继续用一种通用的方法来扩展反射解决方案,这样我就可以了解它了?非常感谢你给出了这个清晰的答案。我理解这种方法,在我的头脑中,这样的解释要简洁得多。RE:建立一个通用的方法——使用类似的方法可能比使用自己的方法更明智。反射包可能很脆弱(由于其性质),无法使用。@elithrar这正是我所需要的。我将研究这一点,以增加可接受的答案。谢谢
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]))
        }
    }
}