先做地图

I am following the go tour and something bothered me.

Maps must be created with make (not new) before use

Fair enough:

map = make(map[int]Cats)

However the very next slide shows something different:

   var m = map[string]Vertex{
    "Bell Labs": Vertex{
        40.68433, -74.39967,
    },
    "Google": Vertex{
        37.42202, -122.08408,
    },
}

This slide shows how you can ignore make when creating maps

Why did the tour say maps have to be created with make before they can be used? Am I missing something here?

Actually the only reason to use make to create a map is to preallocate a specific number of values, just like with slices (except you can't set a cap on a map)

m := map[int]Cats{}
s := []Cats{}
//is the same as
m := make(map[int]Cats)
s := make([]Cats, 0, 0)

However if you know you will have a minimum of X amount of items in a map you can do something like:

m := make(map[int]Cats, 100)// this will speed things up initially

Also check http://dave.cheney.net/2014/08/17/go-has-both-make-and-new-functions-what-gives

So they're actually right that you always need to use make before using a map. The reason it looks like they aren't in the example you gave is that the make call happens implicitly. So, for example, the following two are equivalent:

m := make(map[int]string)
m[0] = "zero"
m[1] = "one"
// Equivalent to:
m := map[int]string{
    0: "zero",
    1: "one",
}

Make vs New

Now, the reason to use make vs new is slightly more subtle. The reason is that new only allocates space for a variable of the given type, whereas make actually initializes it.

To give you a sense of this distinction, imagine we had a binary tree type like this:

type Tree struct {
    root *node
}

type node struct {
    val         int
    left, right *node
}

Now you can imagine that if we had a Tree which was allocated and initialized and had some values in it, and we made a copy of that Tree value, the two values would point to the same underlying data since they'd both have the same value for root.

So what would happen if we just created a new Tree without initializing it? Something like t := new(Tree) or var t Tree? Well, t.root would be nil, so if we made a copy of t, both variables would not point to the same underlying data, and so if we added some elements to the Tree, we'd end up with two totally separate Trees.

The same is true of maps and slices (and some others) in Go. When you make a copy of a slice variable or a map variable, both the old and the new variables refer to the same underlying data, just like an array in Java or C. Thus, if you just use new, and then make a copy and initialize the underlying data later, you'll have two totally separate data structures, which is usually not what you want.