Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

golang - how to initialize a map field within a struct?

I'm confused about the best way to initialize a struct that contains a map. Running this code produces panic: runtime error: assignment to entry in nil map:

package main

type Vertex struct {
   label string
} 

type Graph struct {
  connections map[Vertex][]Vertex
} 

func main() {
  v1 := Vertex{"v1"}
  v2 := Vertex{"v2"}

  g := new(Graph)
  g.connections[v1] = append(g.coonections[v1], v2)
  g.connections[v2] = append(g.connections[v2], v1)
}

One idea is to create a constructor, as in this answer.

Another idea is to use an add_connection method that can initialize the map if it's empty:

func (g *Graph) add_connection(v1, v2 Vertex) {
  if g.connections == nil {
    g.connections = make(map[Vertex][]Vertex)
  }
  g.connections[v1] = append(g.connections[v1], v2)
  g.connections[v2] = append(g.connections[v2], v1)
}

Are there other options? Just wanted to see if there is a commonly-accepted way to do this.

like image 755
Matt Avatar asked Dec 18 '14 18:12

Matt


People also ask

How do I initialize a map in Golang?

Initializing map using map literals: Map literal is the easiest way to initialize a map with data just simply separate the key-value pair with a colon and the last trailing colon is necessary if you do not use, then the compiler will give an error.

How do you initialize a value on a map?

The Static Initializer for a Static HashMap We can also initialize the map using the double-brace syntax: Map<String, String> doubleBraceMap = new HashMap<String, String>() {{ put("key1", "value1"); put("key2", "value2"); }};

How do you initialize an empty map in Golang?

Go by Example: Maps To create an empty map, use the builtin make : make(map[key-type]val-type) . Set key/value pairs using typical name[key] = val syntax. Printing a map with e.g. fmt. Println will show all of its key/value pairs.

How do you set all values on a map to zero?

What exactly do you want to initialize to zero? map's default constructor creates empty map. You may increase map's size only by inserting elements (like m["str1"]=0 or m. insert(std::map<std::string,int>::value_type("str2",0)) ).


3 Answers

I would probably use a constructor to do this:

func NewGraph() *Graph {     var g Graph     g.connections = make(map[Vertex][]Vertex)     return &g } 

I've found this example in the standard image/jpeg package (not with a map though, but with a slice):

type Alpha struct {     Pix []uint8     Stride int     Rect Rectangle }  func NewAlpha(r Rectangle) *Alpha {     w, h := r.Dx(), r.Dy()     pix := make([]uint8, 1*w*h)     return &Alpha{pix, 1 * w, r} } 
like image 196
julienc Avatar answered Oct 01 '22 04:10

julienc


It's very common for code (especially code fully under your control) to assume you initialize the data structure correctly. A struct literal is usually used in this case

g := &Graph{
    connections: make(map[Vertex][]Vertex),
}
like image 20
JimB Avatar answered Oct 01 '22 04:10

JimB


Composite literals work just fine inside a constructor. Contriving an example using the initial question (and naively storing copies of Vertices in the map):

func NewGraph(v1 Vertex, v2 Vertex) *Graph {
    return &Graph{ map[Vertex][]Vertex{ v1: []Vertex{v2}, v2: []Vertex{v1} }}
}

func main() {
  v1 := Vertex{"v1"}
  v2 := Vertex{"v2"}

  g := NewGraph(v1, v2)
  fmt.Println(g)
}

https://play.golang.org/p/Lf4Gomp4tJ

like image 40
durp Avatar answered Oct 01 '22 05:10

durp