go的mapstructure库

github地址:github.com/mitchellh/mapstructure

简介

该库的作用是用于将map转换为结构体,或者将结构体转换为map,该库还做了很多处理时的错误处理。

比如当你获取到json或者gob数据的时候,不知道其具体结构,只能先将其转换为map[string]interface{},然后可以用该库将map[string]interface{}转换为方便处理的struct。

tag的使用

不定义tag的时候,使用字段名,注意字段名大小写敏感。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type User struct {
Username string
}

func main() {
var u User
b := map[interface{}]interface{}{
"Username": "Alice",
}
if err := mapstructure.Decode(b, &u); err != nil {
fmt.Println("decode Interface config failed")
} else {
fmt.Println(u) // {Alice}
}
}

定义tag的话,会使用定义的tag,默认会读mapstructure。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type User struct {
Username string `mapstructure:"byby"`
}

func main() {
var u User
b := map[interface{}]interface{}{
"byby": "Alice",
}
if err := mapstructure.Decode(b, &u); err != nil {
fmt.Println("decode Interface config failed")
} else {
fmt.Println(u) // {Alice}
}
}

也可以自定义读什么tag而不是读默认的mapstructure tag。此时需要使用NewDecoder,指定TagName为自定义的tag,Result部分为目标解码对象。

Decode里传入待解码的值。

PS:多个tag之间直接用空格分割。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type User struct {
Username string `disco:"byby" mapstructure:"hihi"`
}

func main()
var u User
b := map[interface{}]interface{}{
"byby": "Alice",
}
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{TagName: "disco", Result: &u})
if err != nil {
fmt.Println(err)
}
if decoder.Decode(b); err != nil {
fmt.Println(err)
}
fmt.Println(u) // {Alice}
}

指定结构体非嵌套

指定非嵌套结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Person struct {
Name string
}

type Friend struct {
Person Person
}

func main() {
var u Friend
b := map[string]interface{}{
"person": map[string]interface{}{"name": "alice"},
}
if err := mapstructure.Decode(b, &u); err != nil {
fmt.Println("decode Interface config failed")
} else {
fmt.Println(u) // {{alice}}
}
}

如果想指定Persion为非嵌套的,则在Person后面加上 mapstructure:",squash" ,此时输入不需要person的那层了,此时mapstructure看到squash标识,会将输入转化到Person struct里。

运行结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Person struct {
Name string
}

type Friend struct {
Person `mapstructure:",squash"`
}

func main() {
var u Friend
b := map[string]interface{}{
"name": "alice",
}
if err := mapstructure.Decode(b, &u); err != nil {
fmt.Println("decode Interface config failed")
} else {
fmt.Println(u)
}
} // {{"alice"}}

如果传入

1
2
3
map[string]interface{}{
"person": map[string]interface{}{"name": "alice"},
}

则无法decode成功。

获取struct没有定义的字段

如果传入的map有某个字段,而struct没有定义这个字段,则默认情况下会忽略这个字段。

可以加上remain标识,接收一些struct没有定义的字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type Friend struct {
Name string
Other map[string]interface{} `mapstructure:",remain"`
}

func main() {
var u Friend
b := map[string]interface{}{
"name": "bob",
"address": "123 Maple St.",
}
if err := mapstructure.Decode(b, &u); err != nil {
fmt.Println("decode Interface config failed")
} else {
fmt.Println(u)
}
}

其他

忽略struct的字段,定义 `mapstructure:”,omitempty”``

WeakDecode

WeakDecode允许能够最大兼容性的保证Decode的成功,比如传过来的是bool,使用的时候要改成int,比如有的数据库没有bool类型,只能用int表示,此时需要考虑使用WeakDecode。

WeakDecode用法示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func main() {
type Person struct {
Name string
Age int
Emails []string
OK int
Bad int
}

// This input can come from anywhere, but typically comes from
// something like decoding JSON, generated by a weakly typed language
// such as PHP.
input := map[string]interface{}{
"name": 123, // number => string
"age": "42", // string => number
"emails": map[string]interface{}{}, // empty map => empty array
"ok": true,
"bad": false,
}

var result Person
if err := mapstructure.WeakDecode(input, &result); err != nil {
fmt.Println("......err......", err)
return
}
fmt.Println("........result......", result)
}

逆向转换

一般都是将map转换为struct,逆向转换就是将struct转换为map,转换的方法和map转struct类似。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	type Person struct {
Name string
Age int
Emails []string
OK int
Bad int
}

func main() {
p := &Person{
Name: "dj",
Age: 18,
}

var m map[string]interface{}
mapstructure.Decode(p, &m)

data, _ := json.Marshal(m)
fmt.Println(string(data))
}

参考


go的mapstructure库
https://nrbackback.github.io/2022/09/29/go的mapstructure库/
作者
John Doe
发布于
2022年9月29日
许可协议