【问题标题】:What's special about an empty list returned from a map[string][]string从 map[string][]string 返回的空列表有什么特别之处
【发布时间】:2021-09-25 14:46:08
【问题描述】:

这是一个奇怪的情况,我不明白 Go 在做什么。我以一些代码结束,这些代码使用了尚未插入该键的 map 的默认值。

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 全面。这样做的地图的默认值是什么?

【问题讨论】:

    标签: dictionary go slice


    【解决方案1】:

    如果添加另一条打印线:

    fmt.Printf("%#v, %#v, %#v", x, y, z)
    

    一切都会变得清晰。它输出(在Go Playground 上试试):

    []string(nil), []string{}, []string{}
    

    xnil 的切片,y 是具有0 长度的非nil 切片,就像z

    使用不在地图中的键为地图编制索引,会导致地图的值类型为 zero value。在您的情况下,值类型是[]string,它是一个切片类型,切片类型的零值是nil

    reflect.DeepEqual() 记录了nil 切片和非nilslice 不相等:

    请注意,非 nil 空切片和 nil 切片(例如,[]byte{} 和 []byte(nil))并不完全相等。

    【讨论】:

      【解决方案2】:

      首先,快速更正一下,这种数据类型称为“切片”,而不是“列表”。

      当您查找不存在的映射键时,您会得到映射值类型的“零值”。在切片的情况下,零值是nil 切片。 nil 切片的行为通常与空切片非常相似(例如,nil 切片的 len 为零),但它们不被认为是相同的。 Go 中的切片实际上并没有定义相等,因此由reflect.DeepEqual 来决定这里的相等含义。

      您将在解释此处行为的文档中看到此注释:

      当满足以下所有条件时,切片值是高度相等的:它们都是 nil 或都非 nil,它们具有相同的长度,并且它们指向同一底层数组的相同初始条目(即, &x[0] == &y[0]) 或它们对应的元素(直到长度)是完全相等的。 请注意,非 nil 空切片和 nil 切片(例如,[]byte{} 和 []byte(nil))并不完全相等。

      【讨论】:

      • 是的,我习惯用 java 思考
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-12
      • 2016-11-27
      • 1970-01-01
      • 2010-12-28
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多