英文:
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-nil
slice 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论