据我了解,Golang中slicemap的类型在很多方面都相似。它们都是reference(或container)类型。就抽象数据类型而言,它们分别表示一个数组和一个关联数组。

但是,它们的行为却大不相同。

虽然我们可以立即使用声明的切片(追加新项目或重新切片),但是我们不能对新声明的地图执行任何操作。我们必须调用make函数并显式初始化映射。因此,如果某些结构包含一个映射,我们必须为该结构编写一个构造函数。

因此,问题在于,为什么在声明映射时不可能添加一些合成糖并且既分配又初始化内存。

我用谷歌搜索了这个问题,学到了一个新词" avtovivification",但仍然看不出原因。

添加:我不是在谈论结构文字。是的,您可以通过提供诸如m := map[int]int{1: 1}之类的值来显式初始化地图。但是,如果您有一些结构:

不能立即使用结构(所有字段均具有默认值)。必须为SomeStruct创建一个构造函数,该函数必须显式初始化映射。

While we can use a declared slice immediately (append new items or reslice it), we cannot do anything with a newly declared map. We have to call make function and initialize a map explicitly. Therefore, if some struct contains a map we have to write a constructor function for the struct.

这不是真的。切片和贴图的默认值(或更准确地说是零值)均为nil。您可以对nil映射执行"相同"操作,就像对nil切片执行的操作一样。您可以检查nil映射的长度,可以索引nil映射(结果将是映射的值类型的零值),例如以下所有工作:

在Go Playground上尝试一下。

您对零值切片的"感觉"更多是可以在其中添加值。的确如此,但是在幕后,将使用确切的make()内置函数分配新切片,而该函数必须调用地图才能向其中添加条目,并且必须(重新)分配返回的片。因此,零值切片比零值映射"不再准备使用"。 append()只负责必要的(重新)分配和复制。我们可以有一个"等效" addEntry()函数,您可以向其传递一个映射值和键值对,如果传递的映射为nil,它可以分配一个新的映射值并返回它。如果不调用append(),则无法将值添加到nil切片,就像无法将条目添加到nil映射一样。

切片和贴图的零值为nil(而不是初始化的切片或贴图)的主要原因是性能和效率。映射或切片值(变量或结构字段)通常永远不会被使用,或者不会立即使用,因此,如果将它们在声明时分配,那将浪费内存(和某些CPU)资源,更不用说它为垃圾收集器增加了工作量。同样,如果零值将是一个初始化值,则它通常会不够用(例如,0大小的切片无法容纳任何元素),并且在向其添加新元素时通常会将其丢弃(因此初始分配将是完全浪费)。

是的,在某些情况下,您确实想立即使用切片和地图,在这种情况下,您可以自己调用make()或使用复合文字。您也可以使用make()的特殊形式,在其中为地图提供(初始)容量,从而避免将来对地图内部结构进行重组(通常需要进行不可忽略的计算)。自动的非nil默认值无法猜测您需要的容量。

您可以!您正在寻找的是:

:=是声明和分配的,其中var只是声明。