英文:
Why can one not assign to arrays inside maps in Go?
问题
这里有一个简短的示例来说明:
package main
import "fmt"
func main() {
array := [3]int{1, 2, 3}
array[0]++ // 可行
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]++ // 无法编译通过:"cannot assign to arrayMap[0][0]"
sliceMap[0][0]++
fmt.Println(arrayMap)
fmt.Println(sliceMap)
}
为什么如果数组在映射中,我不能修改其内容,即使在映射外部它们是可变的?而对切片来说为什么可以?
英文:
Here's a short example to demonstrate:
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)
}
Why can I not modify the contents of an array if it's inside a map, even though they are mutable outside the map? And why does this work with slices?
答案1
得分: 6
对于映射(maps),它的值是不可寻址的。也就是说,当你使用一个“值类型”(在Go中,数组是“值类型”)时,你不能使用“++”来寻址该值。
但是,如果你使用一个“引用类型”(在Go中,切片是“引用类型”),就可以像你在示例中已经提到的那样。
无论在映射中使用的类型是什么,这个规则都是适用的。
我们可以做的一件事是使用类型的指针地址。例如,如果你取数组的地址,那么它应该可以工作:
Playground: http://play.golang.org/p/XeIThVewWD
package main
import "fmt"
func main() {
array := [3]int{1, 2, 3}
slice := []int{1, 2, 3}
arrayMap := make(map[int]*[3]int) // 使用类型的指针
sliceMap := make(map[int][]int)
arrayMap[0] = &array // 获取类型的指针
sliceMap[0] = slice
arrayMap[0][0]++ // 可以工作,因为它是数组的指针
sliceMap[0][0]++
fmt.Println(*arrayMap[0])
fmt.Println(sliceMap[0])
}
// 输出
[2 2 3]
[2 2 3]
这个代码可以工作,并将array
的[0]
索引递增为2
,与预期相符。
这是因为Go在读取指针时,会优雅地对其进行解引用,并在重新赋值时更新该值。
英文:
For maps, its values are not addressable. That is, when you use a value type
(arrays are value types
in Go), you cannot address the value using ++
.
But, if you use a reference type
(slices are reference types
in Go), you can as you already alluded to in the example.
This holds true regardless of type used in the Map.
One thing we can do instead is to use the ptr address of the type. For example, if you take the address of the array, then it should work:
Playground: http://play.golang.org/p/XeIThVewWD
package main
import "fmt"
func main() {
array := [3]int{1, 2, 3}
slice := []int{1, 2, 3}
arrayMap := make(map[int]*[3]int) // use the pointer to the type
sliceMap := make(map[int][]int)
arrayMap[0] = &array // get the pointer to the type
sliceMap[0] = slice
arrayMap[0][0]++ // works, because it's a pointer to the array
sliceMap[0][0]++
fmt.Println(*arrayMap[0])
fmt.Println(sliceMap[0])
}
// outputs
[2 2 3]
[2 2 3]
This works and increments the [0]
index of array
to 2
, as expected.
It works because Go graciously dereferences pointers for us to its value when read and updates the value during re-assignment.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论