php小编百草今天为大家介绍一种强大的Golang特性——具有不同结构标签集的Unmarshal。在Golang编程中,Unmarshal是一种将数据转换为结构体的过程。但是,当我们的数据源包含不同的结构标签集时,传统的Unmarshal方法可能无法满足需求。因此,我们需要使用具有不同结构标签集的Golang Unmarshal来实现这一功能。本文将详细介绍这个特性的使用方法和注意事项。让我们一起来探索吧!
我正在使用第三方工具的 api,它的 json 中包含自定义键名称。我还必须在两个不同的环境(生产环境和登台环境)上使用 api。不幸的是,api 中的自定义字段在两个环境中具有不同的键名称来表示相同的数据。在下面的示例中,生产环境中的 json 密钥 custom-1
与暂存环境中的 json 密钥 custom-7
完全相同。我想将其中任何一个解组到相同的数据结构中,但我不知道如何进行。我希望有一种方法可以以某种方式覆盖 json.unmarshal()
函数用于在 prod 上使用 json
的标签,但在暂存时使用 jsonstaging
。对我来说,这是最有意义且最简单的解决方案。我猜我必须为我的 jsonobj
类型编写一个自定义 unmarshaljson(data []byte) error
函数,但同样,我不知道如何在自定义函数中实现所需的行为。有人能给我指出正确的方向、一些文档或一些我可以使用的示例吗?
package main import ( "encoding/json" "fmt" ) type jsonobj struct { id string `json:"custom-1" jsonstaging:"custom-7"` desc string `json:"custom-2" jsonstaging:"custom-8"` } func (i jsonobj) string() string { return fmt.sprintf(`{ id: "%s", desc: "%s" }`, i.id, i.desc) } func main() { var jsonprod = `{ "custom-1": "object-a", "custom-2": "test" } ` var jsonstaging = `{ "custom-7": "object-a", "custom-8": "test" } ` var jsonobjprod jsonobj var jsonobjstaging jsonobj json.unmarshal([]byte(jsonprod), &jsonobjprod) json.unmarshal([]byte(jsonstaging), &jsonobjstaging) fmt.println("production: ", jsonobjprod) fmt.println("staging: ", jsonobjstaging) }
当我用 go run 运行它时,我得到
production: { id: "object-a", desc: "test" } staging: { id: "", desc: "" }
这是我当前代码所期望的,但我想得到
Production: { Id: "object-a", Desc: "test" } Staging: { Id: "object-a", Desc: "test" }
我无法修改临时环境或生产环境的 api。
我尝试过创建不同的结构和接口,但是随着字段数量(以及自定义 json 键)的增加(它们会增加),这似乎是维护的噩梦。如果这是唯一的方法,请帮助我,在我决定这可能不是正确的路径之前,我也没有让它发挥作用。
为了将来参考,如果有人想这样做,我想我找到了一种使用内置 reflect
包的方法。
首先,您必须使用 json.unmarshal() 函数,但填充 map[string] 接口{}
而不是您要构建的对象。
然后我编写了一个获取环境和地图的函数。它会遍历实际对象(而不是地图)的新实例中的所有字段,并获取您正在使用的环境的标签。然后它将新对象中的字段设置为 objmap[tag].(f215d538f93896d2fa3ea4137b420524)
。使用标签设置所有字段后,它将返回新对象。
这是我的工作代码:
package main import ( "encoding/json" "fmt" "reflect" ) const ( StagingStructTag = "jsonStaging" ProductionStructTag = "json" ) type jsonObj struct { Id string `json:"custom-1" jsonStaging:"custom-7"` Desc string `json:"custom-2" jsonStaging:"custom-8"` } func (i jsonObj) String() string { return fmt.Sprintf(`{ Id: "%s", Desc: "%s" }`, i.Id, i.Desc) } func main() { var jsonProd = `{ "custom-1": "object-a", "custom-2": "test" } ` var jsonStaging = `{ "custom-7": "object-a", "custom-8": "test" } ` var env string = "staging" var jsonObjProd jsonObj var jsonObjStaging jsonObj var jsonObjProdMap map[string]interface{} var jsonObjStagingMap map[string]interface{} json.Unmarshal([]byte(jsonStaging), &jsonObjStagingMap) json.Unmarshal([]byte(jsonProd), &jsonObjProdMap) jsonObjStaging = BuildJsonObj(env, jsonObjStagingMap) env = "production" jsonObjProd = BuildJsonObj(env, jsonObjProdMap) fmt.Println("Production: ", jsonObjProd) fmt.Println("Staging: ", jsonObjStaging) } func BuildJsonObj(env string, objMap map[string]interface{}) jsonObj { var obj jsonObj var t reflect.Type = reflect.TypeOf(obj) var structTagName string if env == "staging" { structTagName = StagingStructTag } else if env == "production" { structTagName = ProductionStructTag } for i := 0; i < t.NumField(); i++ { var field reflect.StructField = t.Field(i) var tag string var ok bool if tag, ok = field.Tag.Lookup(structTagName); ok { switch field.Name { case "Id": obj.Id = objMap[tag].(string) case "Desc": obj.Desc = objMap[tag].(string) } } } return obj }
以上是具有不同结构标签集的 Golang Unmarshal的详细内容。更多信息请关注PHP中文网其他相关文章!