英文:
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
现在,使用 make
和 new
的原因稍微微妙一些。原因是 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论