简体   繁体   中英

How to make map with empty struct values in go

How to make go map of such structure:


{
    "A": [
        {
            "name": "My name",
            "desc": "aaaa",
            "sub": [] //empty
        },
        {
            "name": "Loc",
            "desc": "bbbb"
            "sub": [
              {
                  "name": "xxxxx",
                  "desc": "aaaa",
              },
              {
                  "name": "yyyyy",
                  "desc": "aaaa",
              },
            ] 
        },
    ],
    "B": [
        {
            "name": "My name b",
            "desc": "cccc",
            "sub": [] //empty
        },
        {
            "name": "tyty",
            "desc": "ffff"
            "sub": [
                {
                    "name": "rrrrrr",
                    "desc": "descrition",
                }
            ] 
        },
    ]
}

I tried to do that but i am not getting it. How make empty struct/array and how make struct in struct?


    type myStruct struct {
        Name string `json:"name"`
        Desc string `json:"desc"`
        // ?? Sub myStruct `json:"sub"`
    }

    m := map[string]interface{}{
        "A": []myStruct{
            {"My name", "aaaa", []???? },
            {"Loc", "bbbb", ??? },
        },
    }

There's some typo's in your original JSON, but using online services like JSON-to-Go yields the following struct definition:

type AutoGenerated struct {
    A []struct {
        Name string        `json:"name"`
        Desc string        `json:"desc"`
        Sub  []interface{} `json:"sub"`
    } `json:"A"`
    B []struct {
        Name string        `json:"name"`
        Desc string        `json:"desc"`
        Sub  []interface{} `json:"sub"`
    } `json:"B"`
}

FYI, below is the cleaned/syntax-corrected version of your JSON I used:

{
    "A": [
        {
            "name": "My name",
            "desc": "aaaa",
            "sub": []
        },
        {
            "name": "Loc",
            "desc": "bbbb",
            "sub": [
              {
                  "name": "xxxxx",
                  "desc": "aaaa"
              },
              {
                  "name": "yyyyy",
                  "desc": "aaaa"
              }
            ]
        }
    ],
    "B": [
        {
            "name": "My name b",
            "desc": "cccc",
            "sub": []
        },
        {
            "name": "tyty",
            "desc": "ffff",
            "sub": [
                {
                    "name": "rrrrrr",
                    "desc": "descrition"
                }
            ] 
        }
    ]
}

You can use the following structure type definition which will work. It avoids the interface{} which is not handy to use to access data. Change the class names to your liking.

package main

import (
    "fmt"
    "encoding/json"
)

var str = `{
    "A": [
        {
            "name": "My name",
            "desc": "aaaa",
            "sub": []
        },
        {
            "name": "Loc",
            "desc": "bbbb",
            "sub": [
              {
                  "name": "xxxxx",
                  "desc": "aaaa"
              },
              {
                  "name": "yyyyy",
                  "desc": "aaaa"
              }
            ]
        }
    ],
    "B": [
        {
            "name": "My name b",
            "desc": "cccc",
            "sub": []
        },
        {
            "name": "tyty",
            "desc": "ffff",
            "sub": [
                {
                    "name": "rrrrrr",
                    "desc": "descrition"
                }
            ] 
        }
    ]
}`

// DescLeaf is leaf of description tree
type DescLeaf struct {
    Name string `json:"name"`
    Desc string `json:"desc"`
}

// DescNode is node of description tree
type DescNode struct {
    Name string `json:"name"`
    Desc string `json:"desc"`
    Sub []DescLeaf `json:"sub"` 
}

// DescRoot is root of description tree
type DescRoot struct {
    A []DescNode `json:"A"`
    B []DescNode `json:"B"`
}

func main() {
    var r DescRoot

    err := json.Unmarshal([]byte(str), &r)
    if err != nil {
        fmt.Println("error:", err)
    } else {
        fmt.Println("done:", r)
    }
}

Outputs

done: {[{My name aaaa []} {Loc bbbb [{xxxxx aaaa} {yyyyy aaaa}]}] [{My name b cccc []} {tyty ffff [{rrrrrr descrition}]}]}

Based on the example JSON, it appears that you are attempting to create a recursive JSON structure. Recursive JSON (and recursive structs) are both very useful, but you have to make sure that you properly build them, or you can run into situations where the structure can not be created in memory.

Let us take a simple example:

type example struct {
    itemOne int64
    subElement example
}

When the program begins to create the struct in memory, it needs to figure out how large it needs to make it. That process goes as such:

  1. figure out how large to make itemOne.
    • Add 8 bytes to the allocation space. (Total: 8)
  2. figure out how large to make subElement.
    1. figure out how large to make subElement-itemOne
      • Add 8 bytes to the allocation space. (Total: 16)
    2. figure out how large to make subElement-subElement
      1. etc.

This process would continue forever until either 1: a stack overflow occurs in the program calculating the memory size, or 2: the total required memory was too large for the program.

In the case of Go, this situation actually has detection built in specifically, so the second step is actually never run. returning ./prog.go:7:6: invalid recursive type example for example.

The solution to this problem is to create a struct where the calculator knows the exact size of everything that it has to add to the struct. To do this, we take advantage of the fact that all structs have in common the size of the pointer to their location in memory.

type example struct {
    itemOne int64
    subElement *example
}

The addition of that single asterisk makes the recursive process from before finite.

  1. figure out how large to make itemOne.
    • Add 8 bytes to the allocation space. (Total: 8)
  2. figure out how large to make subElement pointer .
    • Add 8 bytes to the allocation space (Total 16)
  3. Clean up and allocate 16 bytes.

The values are then set to their defaults. Integers are set to zero, and pointers the nil value (also zero). Passing one of these into the json unmarshal would then create the exact structure you are looking for.

type sub struct {
    Name string     `json:"name"`
    Desc string     `json:"desc"`
    Sub  []*sub     `json:"sub"`
}

full example (Thanks to chmike for doing most of the heavy lifting/formatting for that example)

If you want to do some more digging into golang and pointers there are plenty of resources online such as the official documentation , which has some information spread around, or geeksforgeeks which is a bit more focused with examples. Just be aware of golang's automatic dereferencing

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM