前言
今天介绍一个 go 库 - mergo, mergo 用来方便的合并 struct 和 map ,可以将结构体的字段赋值到map中,可以将map的值赋值给结构体的字段.
Mergo 通过在零值字段中设置默认值来合并同类型的struct 和 map。Mergo 不会合并未导出(私有)字段。它会递归合并任何已导出的字段。它也不会合并map中的结构体(因为它们无法使用 Go 反射寻址)。
Mergo 在很多知名项目中被使用,如 containerd、k8s、loki等。
安装
使用以下命令安装 mergo : go get -u dario.cat/mergo
使用
接下来介绍 mergo 的基础使用和高级用法。
基础使用
mergo 提供了2个主要函数: Merge和Map, Mergo 用来合并2个相同结构的 struct 和 map, Map 用来在结构和map之间赋值。
例子:
package main
import (
"fmt"
"log"
"github.com/imdario/mergo"
)
type redisConfig struct {
Address string
Port int
DB int
UserName string
PassWord string
}
var defaultConfig = redisConfig{
Address: "127.0.0.1",
Port: 6379,
DB: 1,
UserName: "123",
PassWord: "123",
}
func main() {
var config redisConfig
if err := mergo.Merge(&config, defaultConfig); err != nil {
log.Fatal(err)
}
fmt.Println("redis address: ", config.Address)
fmt.Println("redis port: ", config.Port)
fmt.Println("redis db: ", config.DB)
fmt.Println("redis username: ", config.UserName)
fmt.Println("redis password: ", config.PassWord)
var m = make(map[string]interface{})
if err := mergo.Map(&m, defaultConfig); err != nil {
log.Fatal(err)
}
fmt.Println(m)
}
接下来介绍一些高级用法:
覆盖
如果目标结构已经有初始值的情况,Merge/Map 函数不会覆盖已经有的值,如果想要覆盖原有的值,需要使用 WithOverride
参数。
var config redisConfig
config.UserName = "overstarry"
if err := mergo.Merge(&config, defaultConfig, mergo.WithOverride); err != nil {
log.Fatal(err)
}
如果需要检查合并的对象类型是否一致,可以使用 mergo.WithTypeCheck
参数。如果需要覆盖指针,则需使用 WithoutDereference
参数。
slice
如果结构体中的字段是切片类型,覆盖时想要合并2个切片,则使用 WithAppendSlice
参数。
if err := mergo.Merge(&config, defaultConfig, mergo.WithAppendSlice); err != nil {
log.Fatal(err)
}
小结
本文简单的介绍了 mergo 库和常用的一些参数用法,mergo 还提供了一些复杂的参数,有兴趣的读者可以自行研究。