恐慌:在单个简单地图上分配到零地图中的条目

时间:2016-06-03 18:45:08

标签: dictionary go

我的印象是,只有当我们想要分配到双地图时,才会发生在nil地图错误中输入的分配,也就是说,当更高层上的地图试图被分配时不存在,例如:

var mm map[int]map[int]int
mm[1][2] = 3

但它也适用于简单的地图(虽然以结构为关键):

package main

import "fmt"

type COO struct {
    x int
    y int
}

var neighbours map[COO][]COO

func main() {
    for i := 0; i < 30; i++ {
        for j := 0; j < 20; j++ {
            var buds []COO
            if i < 29 {
                buds = append(buds, COO{x: i + 1, y: j})
            }
            if i > 0 {
                buds = append(buds, COO{x: i - 1, y: j})
            }
            if j < 19 {
                buds = append(buds, COO{x: i, y: j + 1})
            }
            if j > 0 {
                buds = append(buds, COO{x: i, y: j - 1})
            }
            neighbours[COO{x: i, y: j}] = buds // <--- yields error
        }
    }


    fmt.Println(neighbours)

}

可能出现什么问题?

2 个答案:

答案 0 :(得分:4)

您需要初始化邻居:var neighbours = make(map[COO][]COO)

请参阅:https://blog.golang.org/go-maps-in-action

中的第二部分

每当您尝试将值插入尚未初始化的地图时,您都会感到恐慌。

答案 1 :(得分:3)

在Golang中,所有内容都初始化为zero value,它是未初始化变量的默认值。

因此,正如它所设想的那样,地图的零值是零。当尝试使用未初始化的地图时,它会发生恐慌。 (一种空指针异常)

有时它会很有用,因为如果您知道某些事物的零值,则不必明确初始化它:

var str string
str += "42"
fmt.Println(str)
// 42 ; A string zero value is ""

var i int
i++
fmt.Println(i)
// 1 ; An int zero value is 0

var b bool
b = !b
fmt.Println(b)
// true ; A bool zero value is false

如果你有Java背景,那就是一样的:基本类型有一个默认值,对象初始化为null;

现在,对于更复杂的类型,例如chanmap,零值为nil,这就是为什么必须使用make来实例化它们的原因。指针也没有零值。数组和切片的情况有点棘手:

var a [2]int
fmt.Println(a)
// [0 0]

var b []int
fmt.Println(b)
// [] ; initialized to an empty slice

编译器知道数组的长度(无法更改)及其类型,因此它已经可以实例化适当的内存量。所有值都初始化为零值(与C不同,您可以在数组中包含任何内容)。对于切片,它会初始化为空切片[],因此您可以正常使用append

现在,对于结构体,它与数组相同。 Go创建一个结构,其所有字段都初始化为零值。它进行了深度初始化,例如:

type Point struct {
    x int
    y int
}

type Line struct {
    a Point
    b Point
}

func main() {
    var line Line
    // the %#v format prints Golang's deep representation of a value
    fmt.Printf("%#v\n", line)
}
// main.Line{a:main.Point{x:0, y:0}, b:main.Point{x:0, y:0}}

最后,interfacefunc类型也初始化为nil。

真的就是这一切。使用复杂类型时,您只需记住初始化它们。唯一的例外是数组,因为你不能make([2]int)

在您的情况下,您有切片贴图,因此您至少需要两个步骤才能放入内容:初始化嵌套切片,并初始化第一个贴图:

var buds []COO
neighbours := make(map[COO][]COO)
neighbours[COO{}] = buds

// alternative (shorter)
neighbours := make(map[COO][]COO)

// You have to use equal here because the type of neighbours[0] is known
neighbours[COO{}] = make([]COO, 0)