Go中的N元树

I am evaluating Go to replace Node.js infrastructure and I am not sure how to create a structure to represent a N-ary tree.

In JavaScript, I parse a file to build up a hierarchy of geographic locations of arbitrary depth. Here is an example:

{
  'country1': {
    'area1': {
      'town1': {}, 
      'town2': {}
    },
    'area2': {
      'town3': {}
    }
  }
}

Towns could expand into specific roads and so on. The hierarchy doesn't have a fixed depth.

How can I create an equivalent structure in Go?

If you're going to have arbitrary depth, then it might be worth it to create a default struct that can be nested:

type area struct {
    Name string
    //Any other area info
    Sections []*area
}

Slices of pointers aren't initialized when creating a new struct object, so it's a valid construct. Declare a.Sections = new([]*area) and append area pointers to it. You will have len(a.Sections) or a for range loop for use in the tree traversal.

Parsing and traversal would be coded recursively, so you would need a type identifier if you treat different areas in different ways.

Let's review the hierarchy.

  • At the top level, you map country names to country objects.

  • Each country object maps area names to area objects.

  • Each area object maps town names to town objects.

In Go, you can implement each level of the hierarchy as a map[string]*Something, with the last level consisting of Town objects that contain various information about towns:

type Country map[string]*Area

type Area map[string]*Town

type Town struct {
    Name                string
    Population          int
    Latitude, Longitude float64
}

The sample hierarchy that you've given in your question would then look like this:

countries := map[string]*Country{
    "country1": &Country{
        "area1": &Area{
            "town1": &Town{},
            "town2": &Town{},
        },
        "area2": &Area{
            "town3": &Town{},
        },
    },
}

If you don't want to map to concrete types, you can use map[string]interface{}, but then you'll need type assertions to work with the values. Here is a code sample taken from Zack Bloom's article on Go and JSON:

var parsed map[string]interface{}
data := []byte(`
    {
        "id": "k34rAT4",
        "age": 24
    }
`)
err := json.Unmarshal(data, &parsed)
idString := parsed["id"].(string)