今天在编译golang项目时,遇到了一个错误。编译器提示 cannot assign to m[1][1]
原项目太大了,不贴了代码大体是这样的
1package main
2
3func main() {
4 m := make(map[int][2]int)
5 a := [2]int{1, 2}
6 m[1] = a
7
8 m[1][1] = 3
9}
编译器提示,不能取到m[1][1]的地址。 但是使用 fmt 能打印出数值
1package main
2
3import "fmt"
4
5func main() {
6 m := make(map[int][2]int)
7 a := [2]int{1, 2}
8 m[1] = a
9
10 // m[1][1] = 3
11 fmt.Println(m[1][1])
12}
打印结果
想了一下,go中的数组和切片(Slice)的和数组(Array)是不一样的,slice是引用传递,array是值传递。把 a
换成slice试一下
代码如下:
1package main
2
3import "fmt"
4
5func main() {
6 m := make(map[int][]int)
7 a := []int{1, 2}
8 m[1] = a
9
10 m[1][1] = 3
11 fmt.Println(m[1][1])
12}
编译通过,没有问题。
问题找到了,是因为值传递导致的问题,解决办法有三种 1 . 像上面一样,使用slice代替array。 2 . 不直接修改数组的值,修改值时,重新创建数组:
1package main
2
3import "fmt"
4
5func main() {
6 m := make(map[int][2]int)
7 a := [2]int{1, 2}
8 m[1] = a
9 fmt.Println(m)
10
11 b := [2]int{3, 4}
12 m[1] = b
13 fmt.Println(m)
14}
结果如下:
3 .使用指向数组的指针:
1package main
2
3import "fmt"
4
5func main() {
6 m := make(map[int]*[2]int)
7 a := &[2]int{1, 2}
8 m[1] = a
9 fmt.Println(m[1])
10
11 m[1][1] = 3
12 fmt.Println(m[1])
13}
结果如下:
没有问题,可以修改值
在网上搜索没有找到深入点分析的文章,最终在stack overflow中找到了一个挺好的分析传送门 原文:
p["HM"]
isn’t quite a regular addressable value: hashmaps can grow at runtime, and then their values get moved around in memory, and the old locations become outdated. If values in maps were treated as regular addressable values, those internals of themap
implementation would get exposed. 英文比较渣,大体看懂了一点意思。我理解的,应该是在程序执行过程中map的长度会变化,为了map值的正确,go语言不允许直接修改map中的值类型结构。
在想另一种情况:
1package main
2
3import "fmt"
4
5func main() {
6 m := make(map[int]T)
7 t := T{
8 One: 1,
9 Two: 2,
10 }
11 m[1] = t
12 fmt.Println(m)
13 m[1].Two = 3
14 fmt.Println(m[1])
15}
16
17type T struct {
18 One int
19 Two int
20}
运行:
编译器提示同样的错误 换成指针后:
1package main
2
3import "fmt"
4
5func main() {
6 m := make(map[int]*T)
7 t := &T{
8 One: 1,
9 Two: 2,
10 }
11 m[1] = t
12 fmt.Println(m[1])
13 m[1].Two = 3
14 fmt.Println(m[1])
15}
16
17type T struct {
18 One int
19 Two int
20}