问题描述
今天在运行golang程序时出现编译错误cannot assign to infoMap[osd.OsdID][0]
。大致和参考链接中的例子类似:
package main
import "fmt"
func main() {
array := [3]int{1, 2, 3}
array[0]++ // Works
slice := make([]int, 3)
for i := range slice {
slice[i] = i + 1
}
arrayMap := make(map[int][3]int)
sliceMap := make(map[int][]int)
arrayMap[0] = array
sliceMap[0] = slice
//arrayMap[0][0]++ // Does not compile: "cannot assign to arrayMap[0][0]"
sliceMap[0][0]++
fmt.Println(arrayMap)
fmt.Println(sliceMap)
}
编译时arrayMap[0][0]++
会出现cannot assign to arrayMap[0][0]
的错误。
分析
Assignments: "Each left-hand side operand must be addressable, a map index expression, or (for = assignments only) the blank identifier."
Address operators: "The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array."
Go's arrays are values. An array variable denotes the entire array; it is not a pointer to the first array element (as would be the case in C). This means that when you assign or pass around an array value you will make a copy of its contents. (To avoid the copy you could pass a pointer to the array, but then that's a pointer to an array, not an array.) One way to think about arrays is as a sort of struct but with indexed rather than named fields: a fixed-size composite value.
Slices are pass by reference, while arrays are pass by value.
当数组被放置在map中时,其实是数组的拷贝,而且当你在map外面使用时也是做了一次拷贝,因此修改数组时并不是真正对原始的数组进行了修改,由于arrayMap[0]
不是an array indexing operation of an addressable array
,所以编译不通过。
sliceMap[0][0]++
类似于:
arr := sliceMap[0]
arr[0] = arr[0] + 1
arr
实际是sliceMap[0]
数据的一份拷贝。
借用参考链接Playground中的例子来说明:
package main
import "fmt"
import "reflect"
func checkArrays() {
array := [3]int{1, 2, 3}
arrayMap := map[int][3]int{
0: array,
}
arr := arrayMap[0]
fmt.Println(reflect.DeepEqual(arr, array))
arr[0]++
fmt.Println(reflect.DeepEqual(arr, array))
}
func checkSlices() {
slice := []int{1, 2, 3}
sliceMap := map[int][]int{
0: slice,
}
slc := sliceMap[0]
fmt.Println(reflect.DeepEqual(slc, slice))
slc[0]++
fmt.Println(reflect.DeepEqual(slc, slice))
}
func main() {
checkArrays()
checkSlices()
}
输出结果为:
true
false
true
true
从结果可以看出arr
是arrayMap[0]
的一份拷贝,修改arr
的值不会对arrayMap[0]
有影响。而slc
和sliceMap[0]
共享底层数据,修改时其实是修改的同一份数据。
References
- Why can one not assign to arrays inside maps in Go?
- Go Slices: usage and internals
- cannot assign to an element of an array which is returned from a function
- Why do I get a “cannot assign” error when setting value to a struct as a value in a map?
- Go Playground
- golang cannot assign to XXX 问题分析
有疑问加站长微信联系(非本文作者)