使用类型查找映射解析通用的 JSON 数据

huangapple go评论82阅读模式
英文:

unmarshalling generic json with a type lookup map

问题

我正在跟进https://stackoverflow.com/questions/28033277/golang-decoding-generic-json-objects-to-one-of-many-formats,作为解组通用JSON的一种方式。然而,我将有许多不同的类型,这些类型可以由其他人添加,因此硬编码的case语句是不可行的。

我也不想将类型硬编码为字符串,而是让使用该库的人选择“查找”名称,以防他们以后想要重命名其底层结构。

我基本上正在寻找这样的东西:

type myInterface interface {
  Something() // 不相关,只是为了向您展示它不是关于interface{}
}

type myBar struct {}       // 实现myInterface
type mySomething struct {} // 实现myInterface

var types = make(map[string]type) // <--- 显然是伪代码 ;)
types["foo:bar"] = myBar       // 由使用该库的人完成
types["1230988"] = mySomething // ...

type storageWrapper struct {
  Type string
  Data json.RawMessage
}

func loadSomething(id string) myInterface {
  buf := db.load(id) // 伪代码,但你明白我的意思
  sw := &storageWrapper{}
  json.Unmarshal(buf, sw)

  // 现在是有趣的部分
  targetType := types[sw.Type]
  thing := &targetType{}
  json.Unmarshal(sw.Data, thing)
  return thing
}

我有一种感觉,我在过度思考整个问题。或者说我试图将Go弯曲成与其底层哲学相冲突的东西。我非常乐意并感谢任何建议,提出对整个问题的不同方法。

英文:

I'm following up on https://stackoverflow.com/questions/28033277/golang-decoding-generic-json-objects-to-one-of-many-formats as a way to unmarshal generic json. I'm going to have a multitude of different types tho which can be added by others, so hardcoding case statements is not feasible.

I also don't want to hardcode the type as a string, but let the ones using the library chose the "lookup" name, in case they want to rename their underlying structs later.

I am basically looking for something like this:

type myInterface interface {
  Something() // irrelevant, just to show you It&#39;s not about interface{}
}

type myBar struct {}       // fulfils myInterface
type mySomething struct {} // fulfils myInterface

var types = make(map[string]type) // &lt;--- Obvious Pseudo code ;)
types[&quot;foo:bar&quot;] = myBar       // done by whoever uses the library
types[&quot;1230988&quot;] = mySomething // ...

type storageWrapper struct {
  Type string
  Data json.RawMessage
}

func loadSomething(id string) myInterface {
  buf := db.load(id) // pseudo code but you get the idea
  sw := &amp;storageWrapper{}
  json.Unmarshal(buf, sw)
  
  // now the interesting part
  targetType := types[sw.Type]
  thing := &amp;targetType{}
  json.Unmarshal(sw.Data, thing)
  return thing
}

I have this feeling that I'm overthinking the whole Problem. Or that I'm trying to bend Go into something that conflicts with its underlying philosophy. I'm very open and thankful for any advice that suggests a different approach to the whole Problem

答案1

得分: 0

types 成为一个 map[string]myInterface,并且要注册一个类型,调用者需要将该类型的空值(而不是引用)存储到该映射中。然后,在解组时,可以通过从映射中复制空值来“获取类型”,对其进行解组,并返回它(或对它的引用)。接口值将负责标识所需的类型。此外,如果用户希望在 JSON 中未提供某些字段时将其默认为非零/空值,他们可以通过在类型映射中的结构体中存储这些值来实现。

英文:

Have types be a map[string]myInterface, and to register a type, have callers store an empty value of that type (not a reference) into the map. Then, to unmarshal, you can "get the type" by copying the empty value out of the map, unmarshaling into it, and returning it (or a reference to it). The interface value will do the job of identifying which type is wanted. Plus, if users want to default some fields to non-zero/empty values in case they're not provided in the JSON, they can actually do that by storing those values within the struct in the type map.

huangapple
  • 本文由 发表于 2016年2月5日 10:02:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/35215110.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定