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].(
。使用标签设置所有字段后,它将返回新对象。
这是我的工作代码:
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的详细内容,更多请关注编程网其它相关文章!