Dictionary 如何检查地图是否包含Go中的密钥?

Dictionary 如何检查地图是否包含Go中的密钥?,dictionary,go,go-map,Dictionary,Go,Go Map,我知道我可以通过 for k, v := range m { ... } 寻找一个密钥,但是有没有更有效的方法来测试一个密钥在地图中的存在 我在中找不到答案。在上搜索,找到了Peter Froehlich于2009年11月15日发布的解决方案 package main import "fmt" func main() { dict := map[string]int {"foo" : 1, "bar" : 2} value, ok := dict["baz"

我知道我可以通过

for k, v := range m { ... }
寻找一个密钥,但是有没有更有效的方法来测试一个密钥在地图中的存在

我在中找不到答案。

在上搜索,找到了Peter Froehlich于2009年11月15日发布的解决方案

package main

import "fmt"

func main() {
        dict := map[string]int {"foo" : 1, "bar" : 2}
        value, ok := dict["baz"]
        if ok {
                fmt.Println("value: ", value)
        } else {
                fmt.Println("key not found")
        }
}
或者,更紧凑地说

if value, ok := dict["baz"]; ok {
    fmt.Println("value: ", value)
} else {
    fmt.Println("key not found")
}
注意,使用这种形式的
if
语句,
ok
变量仅在
if
条件内可见。

单行答案:

if val, ok := dict["foo"]; ok {
    //do something here
}
说明: Go中的
if
语句可以包括条件语句和初始化语句。上述示例使用了以下两种方法:

  • 初始化两个变量-
    val
    将从映射中接收“foo”值或“零值”(在本例中为空字符串),
    ok
    将接收一个bool,如果映射中实际存在“foo”,则该bool将设置为
    true

  • 计算
    ok
    ,如果地图中有“foo”,则为
    true

如果映射中确实存在“foo”,则将执行
If
语句的主体,并且
val
将位于该范围的本地。

此外,您应该阅读。在关于的一节中,他们说:

尝试获取映射值时使用的键不在 映射将返回映射中条目类型的零值。 例如,如果映射包含整数,则查找不存在的 键将返回0。集合可以实现为具有值类型的映射 布尔。将map条目设置为true以将值放入集合中,然后 通过简单的索引来测试它

attended := map[string]bool{
    "Ann": true,
    "Joe": true,
    ...
}

if attended[person] { // will be false if person is not in the map
    fmt.Println(person, "was at the meeting")
}
有时,您需要区分缺少的条目和零值。 是否有“UTC”的条目,或者是0,因为它不在地图中 完全你可以用多重赋值的形式来区分

var seconds int
var ok bool
seconds, ok = timeZone[tz]
var seconds int
var ok bool
seconds, ok = timeZone[tz]
出于显而易见的原因,这被称为“逗号ok”成语。在这个 例如,如果tz存在,则秒数将被适当设置并确定 将是真实的;如果不是,秒将设置为零,ok将为 错。这里有一个函数,它把它和一个很好的错误放在一起 报告:

func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Println("unknown time zone:", tz)
    return 0
}
在不担心实际情况的情况下测试地图中的存在 值时,可以使用空白标识符代替通常的标识符 值的变量

_, present := timeZone[tz]
_, present := timeZone[tz]
然后,跑地图,跑 有什么字符串存在吗?真的 不存在?错误

简短回答 例子 这是一个例子

更长的答案 根据以下章节:

尝试使用映射中不存在的键获取映射值将返回映射中条目类型的零值。例如,如果映射包含整数,则查找不存在的键将返回0

有时,您需要区分缺少的条目和零值。是否有“UTC”的条目,或者该条目是空字符串,因为它根本不在地图中?你可以用多重赋值的形式来区分

var seconds int
var ok bool
seconds, ok = timeZone[tz]
var seconds int
var ok bool
seconds, ok = timeZone[tz]
出于显而易见的原因,这被称为“逗号ok”成语。在本例中,如果tz存在,秒将被适当设置,ok将为真;否则,秒将设置为零,ok将为false。下面是一个将其与一个漂亮的错误报告结合在一起的函数:

func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Println("unknown time zone:", tz)
    return 0
}
func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Println("unknown time zone:", tz)
    return 0
}

测试映射中的存在,不必担心实际值,可以使用空白标识符代替原来的变量值。

_, present := timeZone[tz]
_, present := timeZone[tz]

如其他答案所述,一般解决方案是以特殊形式使用:

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
这很好,很干净。但它有一些限制:它必须是特殊形式的赋值。右侧表达式必须仅为映射索引表达式,左侧表达式列表必须正好包含2个操作数,第一个操作数的值类型是可分配的,第二个操作数的值类型是可分配的。此特殊形式的结果的第一个值将是与键相关联的值,第二个值将告诉您是否在映射中实际存在具有给定键的条目(如果该键存在于映射中)。如果不需要其中一个结果,则左侧表达式列表也可能包含

重要的是要知道,如果索引映射值为
nil
或不包含键,则索引表达式将计算为映射值类型的值。例如:

m := map[int]string{}
s := m[1] // s will be the empty string ""
var m2 map[int]float64 // m2 is nil!
f := m2[2] // f will be 0.0

fmt.Printf("%q %f", s, f) // Prints: "" 0.000000
set := map[string]bool{
    "one": true,
    "two": true,
}

fmt.Println("Contains 'one':", set["one"])

if set["two"] {
    fmt.Println("'two' is in the set")
}
if !set["three"] {
    fmt.Println("'three' is not in the set")
}
试穿一下

因此,如果我们知道在地图中不使用零值,我们可以利用它

例如,如果值类型是
string
,我们知道我们从不在值为空字符串的映射中存储条目(字符串
类型的零值),我们还可以通过比较索引表达式的非特殊形式与零值来测试键是否在映射中:

m := map[int]string{
    0: "zero",
    1: "one",
}

fmt.Printf("Key 0 exists: %t\nKey 1 exists: %t\nKey 2 exists: %t",
    m[0] != "", m[1] != "", m[2] != "")
输出(在上尝试):

在实践中,有许多情况下我们不在地图中存储零值,因此这可以经常使用。例如,接口和函数类型的值为零值
nil
,我们通常不将其存储在映射中。因此,可以通过将某个键与
nil
进行比较来测试该键是否在映射中

使用这种“技术”还有另一个优点:您可以以紧凑的方式检查多个键的存在性(使用特殊的“逗号ok”形式无法做到这一点)。关于这方面的更多信息:

当使用不存在的键进行索引时,获取值类型的零值也允许我们方便地使用带有
bool
值的映射集。例如:

m := map[int]string{}
s := m[1] // s will be the empty string ""
var m2 map[int]float64 // m2 is nil!
f := m2[2] // f will be 0.0

fmt.Printf("%q %f", s, f) // Prints: "" 0.000000
set := map[string]bool{
    "one": true,
    "two": true,
}

fmt.Println("Contains 'one':", set["one"])

if set["two"] {
    fmt.Println("'two' is in the set")
}
if !set["three"] {
    fmt.Println("'three' is not in the set")
}
它输出(在屏幕上试用):

请参见相关内容:

这里的更好方法

if _, ok := dict["foo"]; ok {
    //do something here
}
它在下面提到

赋值中使用的map[K]V类型映射上的索引表达式 或特殊窗体的初始化

v, ok = a[x] 
v, ok := a[x] 
var v, ok = a[x]
生成一个额外的非类型化布尔值。如果出现以下情况,则ok的值为真 键x出现在地图中,否则为false


两值赋值可以是