一、包简介
mapstructure用于将通用的map[string]interface{}解码到对应的 Go 结构体中,或者执行相反的操作。很多时候,解析来自多种源头的数据流时,我们一般事先并不知道他们对应的具体类型。只有读取到一些字段之后才能做出判断。这时,我们可以先使用标准的encoding/json库将数据解码为map[string]interface{}类型,然后根据标识字段利用mapstructure库转为相应的 Go 结构体以便使用.
二、安装
#不能下载可以设置goproxy
go get github.com/mitchellh/mapstructure
https://pkg.go.dev/github.com/mitchellh/mapstructure
三、介绍
解码:
解码采用输入结构并使用反射将其转换为输出结构。输出必须是指向map或struct的指针。
type Person struct {
Name string
Age int
Emails []string
Extra map[string]string
}
// 此输入可以来自任何地方,但通常来自解码 JSON 之类的东西,我们最初不太确定结构。
input := map[string]interface{}{
"name": "Mitchell",
"age": 91,
"emails": []string{"one", "two", "three"},
"extra": map[string]string{
"twitter": "mitchellh",
},
}
var result Person
//解码
err := Decode(input, &result)
if err != nil {
panic(err)
}
fmt.Printf("%#v", result)
嵌套结构体
// 允许使用 squash 标签压缩多个嵌入式结构。这是通过创建多种类型的复合结构并解码到其中来演示的。在这种情况下,一个人可以随身携带Family和Location,以及他们自己的Name。
type Family struct {
LastName string
}
type Location struct {
City string
}
type Person struct {
Family `mapstructure:",squash"`
Location `mapstructure:",squash"`
FirstName string
}
input := map[string]interface{}{
"FirstName": "Mitchell",
"LastName": "Hashimoto",
"City": "San Francisco",
}
var result Person
err := Decode(input, &result)
if err != nil {
panic(err)
}
fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City)
元数据
type Person struct {
Name string
Age int
}
// 此输入可以来自任何地方,但通常来自解码 JSON 之类的东西,我们最初不太确定结构。
input := map[string]interface{}{
"name": "Mitchell",
"age": 91,
"email": "foo@bar.com",
}
// 对于元数据,我们制作了一个更高级的解码器配置,以便我们可以更精细地配置所使用的解码器。在这种情况下,我们只是告诉解码器我们要跟踪元数据。
var md Metadata
var result Person
config := &DecoderConfig{
Metadata: &md,
Result: &result,
}
decoder, err := NewDecoder(config)
if err != nil {
panic(err)
}
if err := decoder.Decode(input); err != nil {
panic(err)
}
fmt.Printf("Unused keys: %#v", md.Unused)
//运行结果: Unused keys: []string{"email"}
//email没有使用,可以查看Metadata结构体的其他字段解锁更多功能
添加省略空值的注释
// 添加省略空注释以避免空值的映射键
type Family struct {
LastName string
}
type Location struct {
City string
}
type Person struct {
*Family `mapstructure:",omitempty"`
*Location `mapstructure:",omitempty"`
Age int
FirstName string
}
result := &map[string]interface{}{}
input := Person{FirstName: "Somebody"}
err := Decode(input, &result)
if err != nil {
panic(err)
}
fmt.Printf("%+v", result)
未知的数据可以放在具有”,remain”标签的 map[string]interface{},字段下,该字段必须是map[string]interface{}类型
// 请注意,结构类型中定义的映射结构标记可以指示值映射到哪些字段。
type Person struct {
Name string
Age int
Other map[string]interface{} `mapstructure:",remain"`
}
input := map[string]interface{}{
"name": "Mitchell",
"age": 91,
"email": "mitchell@example.com",
}
var result Person
err := Decode(input, &result)
if err != nil {
panic(err)
}
fmt.Printf("%#v", result)
tag,类似json解析的重命名
// 请注意,结构类型中定义的映射结构标记可以指示值映射到哪些字段。
type Person struct {
Name string `mapstructure:"person_name"`
Age int `mapstructure:"person_age"`
}
input := map[string]interface{}{
"person_name": "Mitchell",
"person_age": 91,
}
var result Person
err := Decode(input, &result)
if err != nil {
panic(err)
}
fmt.Printf("%#v", result)
弱类型语言数据的处理
type Person struct {
Name string
Age int
Emails []string
}
// 该输入可以来自任何地方,但通常来自解码JSON,该json由弱类型的语言(例如PHP)生成。
input := map[string]interface{}{
"name": 123, // number => string
"age": "42", // string => number
"emails": map[string]interface{}{}, // empty map => empty array
}
var result Person
config := &DecoderConfig{
WeaklyTypedInput: true,
Result: &result,
}
decoder, err := NewDecoder(config)
if err != nil {
panic(err)
}
err = decoder.Decode(input)
if err != nil {
panic(err)
}
fmt.Printf("%#v", result)
//也可使用weakdecode函数
其他函数见文档
文档更新时间: 2022-12-09 17:27 作者:张尚