gconv.Map supports converting any map or struct/ *struct type to the commonly used map[string]interface{} type. When the conversion parameter is of type struct/ *struct, it automatically recognizes the c/gconv/json tags of struct, and you can specify custom conversion tags and the priority of multiple tag parsing via the second parameter tags of the Map method. If the conversion fails, it returns nil.

Type Conversion - Map - 图1tip

Property Tags: When converting struct/ *struct types, it supports c/gconv/json property tags, as well as - and omitempty tag properties. When using the - tag property, it means that the property will not be converted. When using the omitempty tag property, it means that the conversion will not be performed when the property is empty (nil pointer, number 0, string "", empty array [], etc.). Please refer to the examples below for details.

Common conversion methods:

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

Among them, MapDeep supports recursive conversion, which will recursively convert the struct/ *struct objects within the properties.

Type Conversion - Map - 图2tip

For more map-related conversion methods, please refer to the interface documentation: https://pkg.go.dev/github.com/gogf/gf/v2/util/gconv

Basic Example

  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. // Object
  12. g.Dump(gconv.Map(User{
  13. Uid: 1,
  14. Name: "john",
  15. }))
  16. // Object pointer
  17. g.Dump(gconv.Map(&User{
  18. Uid: 1,
  19. Name: "john",
  20. }))
  21. // Any map type
  22. g.Dump(gconv.Map(map[int]int{
  23. 100: 10000,
  24. }))
  25. }

After execution, the terminal outputs:

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

Property Tags

We can customize the map key name after conversion via the c/gconv/json tag. When multiple tags exist, the priority is determined by the order of gconv/c/json tags.

  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. }

After execution, the terminal outputs:

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

Custom Tags

Besides, we can also customize the tag names of struct properties and specify the tag priority during map conversion via the second parameter.

  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. }

After execution, the output result is:

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

Recursive Conversion

When the parameter is of map/ struct/ *struct type, if the key value/property is an object (or an object pointer) and is not an embedded struct without any alias tags bound, the Map method will convert the object as a key-value in the result. We can use the MapDeep method to recursively convert sub-objects of the parameters, i.e., converting properties to map type as well. Let’s look at an example.

  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. }

After execution, the terminal output is:

  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 {}

Can you see the difference?