英文:
What's special about an empty list returned from a map[string][]string
问题
这里有一个奇怪的情况,我不明白Go语言在做什么。我最终得到了一些代码,使用了尚未插入该键的映射的默认值。
package main
import (
"fmt"
"reflect"
)
func main() {
mmm := map[string][]string{}
nnn := map[string][]string {
"a": {},
}
x := mmm["a"]
y := nnn["a"]
z := []string{}
fmt.Println(reflect.DeepEqual(x,y))
fmt.Println(reflect.DeepEqual(x,z))
fmt.Println(reflect.DeepEqual(y,z))
fmt.Printf("%T, %T, %T", x, y, z)
}
我得到了意外的输出
false
false
true
[]string, []string, []string
我本来期望的是全都是true。这是关于映射的默认值的特性导致的。
英文:
Here's a weird situation where I don't understand what Go is doing. I ended with some code that used the default value of map that hasn't had that key inserted into it yet.
package main
import (
"fmt"
"reflect"
)
func main() {
mmm := map[string][]string{}
nnn := map[string][]string {
"a": {},
}
x := mmm["a"]
y := nnn["a"]
z := []string{}
fmt.Println(reflect.DeepEqual(x,y))
fmt.Println(reflect.DeepEqual(x,z))
fmt.Println(reflect.DeepEqual(y,z))
fmt.Printf("%T, %T, %T", x, y, z)
}
I get the unexpected output
false
false
true
[]string, []string, []string
where I would expect true across the board. What is it about the default value of a map that does this?
答案1
得分: 3
如果你添加另一行打印代码:
fmt.Printf("%#v, %#v, %#v", x, y, z)
一切都会变得清晰。它的输出结果是(在Go Playground上尝试一下):
[]string(nil), []string{}, []string{}
x 是一个 nil 切片,而 y 是一个非 nil 切片,长度为 0,就像 z 一样。
如果使用一个不在 map 中的键进行索引,它会返回 map 的值类型的零值。在你的情况下,值类型是 []string,它是一个切片类型,切片类型的零值是 nil。
而 reflect.DeepEqual() 文档说明了 nil 切片和非 nil 切片是不相等的:
注意,非
nil的空切片和nil切片(例如,[]byte{}和[]byte(nil))不是深度相等的。
英文:
If you add another printing line:
fmt.Printf("%#v, %#v, %#v", x, y, z)
It'll all become clear. It outputs (try it on the Go Playground):
[]string(nil), []string{}, []string{}
x is a slice being nil, and y is a non-nil slice having 0 length, just like z.
Indexing a map with a key that's not in the map, it results in the zero value for the value type of the map. In your case the value type is []string, its a slice type, and zero value for slice types is nil.
And reflect.DeepEqual() documents that a nil slice and a non-nilslice are not equal:
> Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)) are not deeply equal.
答案2
得分: 2
首先,只是一个小的修正,这种数据类型被称为“切片”,而不是“列表”。
当你查找一个不存在的映射键时,你会得到映射值类型的“零值”。对于切片来说,零值是一个nil切片。一个nil切片通常的行为很像一个空切片(例如,nil切片的长度为零),但它们并不被认为是相同的。在Go语言中,切片的相等性实际上是没有定义的,所以由reflect.DeepEqual来决定这里的相等性的含义。
你会在文档中看到这个说明来解释这种行为:
> 当以下所有条件都为真时,切片值是深度相等的:它们都是nil或都是非nil的,它们具有相同的长度,并且它们要么指向相同底层数组的相同初始条目(即,&x[0] == &y[0]),要么它们的对应元素(长度上限)是深度相等的。注意,非nil的空切片和nil切片(例如,[]byte{}和[]byte(nil))不是深度相等的。
英文:
First, just a quick correction, this kind of data type is called a "slice", not a "list".
When you look-up a map key that doesn't exist, you get the "zero value" of the map's value type. In the case of slices, the zero-value is a nil slice. A nil slice generally behaves much like an empty slice (for example, the len of a nil slice is zero), but they are not considered to be the same. Equality is not actually defined for slices in Go, so it is up to reflect.DeepEqual to decide what equality means here.
You'll see this note in the documentation explaining the behaviour here:
> Slice values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they point to the same initial entry of the same underlying array (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal. Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)) are not deeply equal.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论