Go中的地图初始化

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

然而,他们的行为却截然不同。

var s []int
var m map[int]int

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

所以,问题是为什么不能在声明映射时添加一些语法糖并同时分配和初始化内存。

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

我不是在谈论结构文字。是的,您可以通过提供诸如m := map[int]int{1: 1}. 但是,如果您有一些结构:

package main


import (

    "fmt"

)


type SomeStruct struct {

    someField map[int]int

    someField2 []int

}


func main() {

    s := SomeStruct{}

    s.someField2 = append(s.someField2, -1) // OK

    s.someField[0] = -1 // panic: assignment to entry in nil map

    fmt.Println(s)

}

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


catspeake
浏览 169回答 2
2回答

杨魅力

虽然我们可以立即使用声明的切片(附加新项或重新切片),但我们不能对新声明的映射做任何事情。我们必须显make式调用函数并初始化地图。因此,如果某个结构包含一个映射,我们必须为该结构编写一个构造函数。这不是真的。切片和映射的默认值(或更准确地说是零值nil)是. nil您可以对地图执行与对切片执行的“相同”操作nil。你可以检查nil地图的长度,你可以索引nil地图(结果将是地图值类型的零值),例如以下所有工作:var m map[int]intfmt.Println(m == nil) // Prints truefmt.Println(len(m))   // Prints 0fmt.Println(m[2])     // Prints 0在Go Playground上尝试一下。您对零值切片的更多“感觉”是您可以为其添加值。这是事实,但在幕后,将使用make()您必须为地图调用的确切内置函数来分配一个新切片,以便向其添加条目,并且您必须(重新)分配返回的切片。因此,零值切片与零值映射“无法使用”。append()只负责必要的(重新)分配和复制。我们可以有一个“等效”addEntry()函数,您可以将映射值和键值对传递给它,如果传递的映射是nil,它可以分配一个新的映射值并返回它。如果不调用append(),就不能向nil切片添加值,就像不能向nil映射添加条目一样。nil切片和映射的零值(而不是初始化的切片或映射)的主要原因是性能和效率。通常,映射或切片值(变量或结构字段)永远不会被使用,或者不会立即使用,因此如果它们在声明时分配,那将是内存(和一些 CPU)的浪费资源,更不用说它为垃圾收集器提供了更多工作。此外,如果零值是一个初始化值,它通常是不够的(例如,一个 0 大小的切片不能容纳任何元素),并且当您向它添加新元素时它通常会被丢弃(因此初始分配将是完全浪费)。是的,有些情况下您确实想立即使用切片和映射,在这种情况下您可以调用make()自己,或使用复合文字。您还可以使用特殊形式make()为地图提供(初始)容量,避免未来地图内部结构的重组(这通常需要不可忽略的计算)。自动非nil默认值无法猜测您需要的容量。

海绵宝宝撒

你可以!您正在寻找的是:package mainimport "fmt"func main() {    v := map[int]int{}    v[1] = 1    v[2] = 2    fmt.Println(v)}:=是声明和分配,其中 asvar只是声明。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go