在开始之前先制作地图。

huangapple go评论73阅读模式
英文:

Making maps in go before anything

问题

我正在为你翻译以下内容:

我正在按照Go语言教程学习,有一件事困扰着我。

> 在使用之前,必须使用make(而不是new)创建映射

很好:

map = make(map[int]Cats)

然而,下一张幻灯片展示了不同的内容:

   var m = map[string]Vertex{
    "贝尔实验室": Vertex{
        40.68433, -74.39967,
    },
    "谷歌": Vertex{
        37.42202, -122.08408,
    },
}

这张幻灯片展示了在创建映射时可以忽略make的方法。

为什么教程说在使用映射之前必须使用make来创建呢?我有什么地方理解错了吗?

英文:

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?

答案1

得分: 4

实际上,使用make创建映射的唯一原因是预先分配特定数量的值,就像切片一样(除了你不能为映射设置容量)。

m := map[int]Cats{}
s := []Cats{}
//与下面的代码等价
m := make(map[int]Cats)
s := make([]Cats, 0, 0)

然而,如果你知道映射中至少会有X个项目,你可以这样做:

m := make(map[int]Cats, 100) // 这样会加快初始速度

另请参考http://dave.cheney.net/2014/08/17/go-has-both-make-and-new-functions-what-gives。

英文:

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

答案2

得分: 1

所以,他们实际上是正确的,你在使用 map 之前总是需要使用 make。之所以在你给出的示例中看起来好像没有使用 make,是因为 make 调用是隐式发生的。因此,例如,下面的两种方式是等价的:

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

make 和 new

现在,使用 makenew 的原因稍微微妙一些。原因是 new 只为给定类型的变量分配空间,而 make 则实际上对其进行初始化。

为了让你理解这个区别,想象一下我们有一个二叉树类型,如下所示:

type Tree struct {
    root *node
}

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

现在你可以想象,如果我们有一个已经分配和初始化并且其中有一些值的 Tree,然后我们复制了那个 Tree 值,那么这两个值将指向相同的底层数据,因为它们都具有相同的 root 值。

那么,如果我们只是创建一个未初始化的 Tree 会发生什么呢?类似于 t := new(Tree)var t Tree 这样的情况?嗯,t.root 将为 nil,因此如果我们复制 t,两个变量将不指向相同的底层数据,因此如果我们向 Tree 添加一些元素,我们将得到两个完全独立的 Tree

在 Go 中,对于 map 和 slice(以及其他一些类型)也是如此。当你复制一个切片变量或映射变量时,旧变量和新变量都引用相同的底层数据,就像 Java 或 C 中的数组一样。因此,如果你只使用 new,然后复制并在稍后初始化底层数据,你将得到两个完全独立的数据结构,这通常不是你想要的。

英文:

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.

huangapple
  • 本文由 发表于 2014年8月23日 21:47:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/25462624.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定