【问题标题】:How to use struct keys in a map?如何在地图中使用结构键?
【发布时间】:2022-01-09 17:49:56
【问题描述】:

我在不使用 ORM 的情况下实现了一些数据库逻辑。

我能以某种方式在结构键和数据库枚举之间创建映射吗?

type Message struct {
    SomeKey string
    SomeOtherKey string
}

MessageToDBEnum: = map[ ? MessageKey] string {
    SomeKey: "some_key",
    SomeOtherKey: "some_other_key"
}
  • 我以后可以动态地使用映射键(例如在遍历映射时)来设置/获取结构值吗?
  • 我还能以某种方式确保MessageToDBEnum 是详尽无遗的(包括 Message 的所有公钥)吗?

【问题讨论】:

标签: dictionary go struct enums


【解决方案1】:

您本质上想将结构转换为映射,反之亦然。有 3rd 方库可以做到这一点,例如github.com/mitchellh/mapstructure.

但我们也可以自己做,没那么难。我们可以使用反射来做到这一点。在不检查错误的情况下,以下是 struct 到 map 转换的精髓:

func struct2Map(x interface{}) map[string]interface{} {
    m := map[string]interface{}{}

    v := reflect.ValueOf(x)
    t := reflect.TypeOf(x)
    for i := 0; i < v.NumField(); i++ {
        m[t.Field(i).Name] = v.Field(i).Interface()
    }

    return m
}

你可以这样使用它:

msg := Message{
    SomeKey:      "v1",
    SomeOtherKey: "v2",
}

m := struct2Map(msg)
fmt.Println(m)

哪些输出:

map[SomeKey:v1 SomeOtherKey:v2]

向后转换更简单,但要知道,要修改结构的函数,必须将指针传递给它。同样,不检查可能的错误,它的本质是:

func map2Struct(m map[string]interface{}, d interface{}) {
    s := reflect.ValueOf(d).Elem()
    for k, v := range m {
        s.FieldByName(k).Set(reflect.ValueOf(v))
    }
}

使用它:

var msg2 Message
map2Struct(m, &msg2)
fmt.Printf("%+v\n", msg2)

哪些输出:

{SomeKey:v1 SomeOtherKey:v2}

试试Go Playground上的例子。

您可以将验证构建到这些转换函数中,并在发现无效值时返回错误或使用默认值/零值。

【讨论】:

  • 谢谢!我想使用结构字段,例如 SomeKey 作为映射键,而不是整个结构
  • @GeriTol 使用 struct 字段与使用单个 string 作为键没有什么不同,请参阅答案的后半部分。
  • 我需要SomeKey 作为映射键而不是some_key。映射需要能够将结构持久化到数据库并稍后将其检索回来。
  • @GeriTol 我重写了答案。
  • 谢谢!将审查它。在您提交答案之前,刚刚在问题的 cmets 中发布了一些关于同一库的说明。
猜你喜欢
  • 2015-04-01
  • 2011-10-30
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-17
  • 1970-01-01
  • 2011-11-04
相关资源
最近更新 更多