gconv.Map 支持将任意的 mapstruct/ *struct 类型转换为常用的 map[string]interface{} 类型。当转换参数为 struct/ *struct 类型时,支持自动识别 structc/gconv/json 标签,并且可以通过 Map 方法的第二个参数 tags 指定自定义的转换标签,以及多个标签解析的优先级。如果转换失败,返回 nil

类型转换-Map转换 - 图1提示

属性标签:当转换 struct/ *struct 类型时,支持 c/gconv/json 属性标签,也支持 -omitempty 标签属性。当使用 - 标签属性时,表示该属性不执行转换;当使用 omitempty 标签属性时,表示当属性为空时(空指针 nil, 数字 0, 字符串 "", 空数组 [] 等)不执行转换。具体请查看随后示例。

常用转换方法:

  1. func Map(value interface{}, tags ...string) map[string]interface{}
  2. func MapDeep(value interface{}, tags ...string) map[string]interface{}

其中, MapDeep 支持递归转换,即会递归转换属性中的 struct/ *struct 对象。

类型转换-Map转换 - 图2提示

更多的 map 相关转换方法请参考接口文档: https://pkg.go.dev/github.com/gogf/gf/v2/util/gconv

基本示例

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/util/gconv"
  5. )
  6. func main() {
  7. type User struct {
  8. Uid int `c:"uid"`
  9. Name string `c:"name"`
  10. }
  11. // 对象
  12. g.Dump(gconv.Map(User{
  13. Uid: 1,
  14. Name: "john",
  15. }))
  16. // 对象指针
  17. g.Dump(gconv.Map(&User{
  18. Uid: 1,
  19. Name: "john",
  20. }))
  21. // 任意map类型
  22. g.Dump(gconv.Map(map[int]int{
  23. 100: 10000,
  24. }))
  25. }

执行后,终端输出:

  1. {
  2. "name": "john",
  3. "uid": 1,
  4. }
  5. {
  6. "name": "john",
  7. "uid": 1,
  8. }
  9. {
  10. "100": 10000,
  11. }

属性标签

我们可以通过 c/gconv/json 标签来自定义转换后的 map 键名,当多个标签存在时,按照 gconv/c/json 的标签顺序进行优先级识别。

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/util/gconv"
  5. )
  6. func main() {
  7. type User struct {
  8. Uid int
  9. Name string `c:"-"`
  10. NickName string `c:"nickname, omitempty"`
  11. Pass1 string `c:"password1"`
  12. Pass2 string `c:"password2"`
  13. }
  14. user := User{
  15. Uid: 100,
  16. Name: "john",
  17. Pass1: "123",
  18. Pass2: "456",
  19. }
  20. g.Dump(gconv.Map(user))
  21. }

执行后,终端输出:

  1. {
  2. "Uid": 100,
  3. "password1": "123",
  4. "password2": "456",
  5. "nickname": "",
  6. }

自定义标签

此外,我们也可以给 struct 的属性自定义自己的标签名称,并在 map 转换时通过第二个参数指定标签优先级。

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/util/gconv"
  5. )
  6. func main() {
  7. type User struct {
  8. Id int `c:"uid"`
  9. Name string `my-tag:"nick-name" c:"name"`
  10. }
  11. user := &User{
  12. Id: 1,
  13. Name: "john",
  14. }
  15. g.Dump(gconv.Map(user, "my-tag"))
  16. }

执行后,输出结果为:

  1. {
  2. "nick-name": "john",
  3. "uid": 1,
  4. }

递归转换

当参数为 map/ struct/ *struct 类型时,如果键值/属性为一个对象(或者对象指针)时,并且不是 embedded 结构体且没有任何的别名标签绑定, Map 方法将会将对象转换为结果的一个键值。我们可以使用 MapDeep 方法递归转换参数的子对象,即把属性也转换为 map 类型。我们来看个例子。

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/v2/frame/g"
  5. "github.com/gogf/gf/v2/util/gconv"
  6. "reflect"
  7. )
  8. func main() {
  9. type Base struct {
  10. Id int `c:"id"`
  11. Date string `c:"date"`
  12. }
  13. type User struct {
  14. UserBase Base `c:"base"`
  15. Passport string `c:"passport"`
  16. Password string `c:"password"`
  17. Nickname string `c:"nickname"`
  18. }
  19. user := &User{
  20. UserBase: Base{
  21. Id: 1,
  22. Date: "2019-10-01",
  23. },
  24. Passport: "john",
  25. Password: "123456",
  26. Nickname: "JohnGuo",
  27. }
  28. m1 := gconv.Map(user)
  29. m2 := gconv.MapDeep(user)
  30. g.Dump(m1, m2)
  31. fmt.Println(reflect.TypeOf(m1["base"]))
  32. fmt.Println(reflect.TypeOf(m2["base"]))
  33. }

执行后,终端输出结果为:

  1. {
  2. "base": {
  3. Id: 1,
  4. Date: "2019-10-01",
  5. },
  6. "passport": "john",
  7. "password": "123456",
  8. "nickname": "JohnGuo",
  9. }
  10. {
  11. "base": {
  12. "id": 1,
  13. "date": "2019-10-01",
  14. },
  15. "passport": "john",
  16. "password": "123456",
  17. "nickname": "JohnGuo",
  18. }
  19. main.Base
  20. map[string]interface {}

看出来差别了吗?