如何检查地图是否包含Go中的键?

时间:2010-01-12 16:18:20

标签: dictionary go go-map

我知道我可以迭代地图m

for k, v := range m { ... }

并寻找一个键但是有没有更有效的方法来测试一个键在地图中的存在?

我在language spec找不到答案。

12 个答案:

答案 0 :(得分:1102)

一行答案:

if val, ok := dict["foo"]; ok {
    //do something here
}

说明:

Go中的

if语句可以包含条件和初始化语句。上面的例子使用了两个:

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

  • 评估ok,如果“foo”在地图中,则为true

如果地图中确实存在“foo”,则if语句的主体将被执行,val将是该范围的本地。

答案 1 :(得分:92)

编辑:以下答案在Go 1之前。从Go 1开始,它不再准确/有效。


除了The Go Programming Language Specification之外,您还应该阅读Effective Go。在maps部分,他们说,除其他外:

“尝试使用地图中不存在的键获取地图值将导致程序崩溃,但有一种方法可以安全地使用多次分配。”

var seconds int
var ok bool
seconds, ok = timeZone[tz]

“要测试地图中的状态而不必担心实际值,可以使用空白标识符,一个简单的下划线(_)。空白标识符可以使用任何类型的任何值分配或声明,值为为了测试地图中的存在,使用空白标识符代替值的常用变量。“

_, present := timeZone[tz]

答案 2 :(得分:45)

go-nuts email list上搜索并找到了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语句形式,valueok变量仅在if条件中可见。

答案 3 :(得分:21)

简答

_, exists := timeZone[tz]    // Just checks for key existence
val, exists := timeZone[tz]  // Checks for key existence and retrieves the value

实施例

这是一个example at the Go Playground

更长的答案

根据MapsEffective Go部分:

  

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

     

有时您需要区分缺失的条目和零值。是否有“UTC”的条目,或者是空字符串,因为它根本不在地图中?您可以通过多种分配形式进行区分。

var seconds int
var ok bool
seconds, ok = timeZone[tz]
     

由于显而易见的原因,这被称为“逗号确定”成语。在这个例子中,如果存在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
}
     

要测试地图中的状态而不必担心实际值,可以使用空白标识符(_)代替值的常用变量。

_, present := timeZone[tz]

答案 4 :(得分:10)

正如其他答案所述,一般的解决方案是在特殊形式的index expression中使用assignment

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]

这很干净。但它有一些限制:它必须是特殊形式的赋值。右侧表达式必须只是映射索引表达式,左侧表达式列表必须包含2个操作数,第一个值类型可赋值,第二个值可赋值bool。此特殊表单索引表达式的结果的第一个值将是与键关联的值,第二个值将指示映射中是否存在具有给定键的条目(如果键存在于映射中)。如果不需要其中一个结果,左侧表达式列表也可能包含blank identifier

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

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

Go Playground上尝试。

因此,如果我们知道我们不在地图中使用零值,我们就可以利用这一点。

例如,如果值类型为string,并且我们知道我们永远不会在地图中存储值为空字符串的条目(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] != "")

输出(在Go Playground上尝试):

Key 0 exists: true
Key 1 exists: true
Key 2 exists: false

实际上,在很多情况下,我们不会在地图中存储零值,因此可以经常使用。例如,接口和函数类型的值为nil,我们通常不会将其存储在映射中。因此,通过将密钥与nil进行比较,可以测试密钥是否在地图中。

使用这种“技术”还有另一个优点:你可以用一种紧凑的方式检查多个键的存在(你不能用特殊的“逗号ok”形式)。更多相关信息:Check if key exists in multiple maps in one condition

答案 5 :(得分:6)

更好的方式

if _, ok := dict["foo"]; ok {
    //do something here
}

答案 6 :(得分:4)

"Index expressions"下提及。

  

分配中使用的类型map [K] V的映射a上的索引表达式   或初始化特殊表格

v, ok = a[x] 
v, ok := a[x] 
var v, ok = a[x]
     

产生一个额外的无类型布尔值。如果是,则ok的值为true   键x出现在地图中,否则为false。

答案 7 :(得分:3)

    var empty struct{}
    var ok bool
    var m map[string]struct{}
    m = make(map[string]struct{})
    m["somestring"] = empty


    _, ok = m["somestring"]
    fmt.Println("somestring exists?", ok) 
    _, ok = m["not"]
    fmt.Println("not exists?", ok)

然后,去运行maps.go somestring存在?真正 不存在?假

答案 8 :(得分:1)

两个值的分配可用于此目的。请在下面查看我的示例程序

package main

import (
    "fmt"
)

func main() {
    //creating a map with 3 key-value pairs
    sampleMap := map[string]int{"key1": 100, "key2": 500, "key3": 999}
    //A two value assignment can be used to check existence of a key.
    value, isKeyPresent := sampleMap["key2"]
    //isKeyPresent will be true if key present in sampleMap
    if isKeyPresent {
        //key exist
        fmt.Println("key present, value =  ", value)
    } else {
        //key does not exist
        fmt.Println("key does not exist")
    }
}

答案 9 :(得分:1)

value , ok = map[key]; if ok {
    fmt.Println("Key Present ")
    }
    else {
    fmt.Println(" Key Not Present " )
}

答案 10 :(得分:0)

看看这段代码

    nameMap := make(map[string]int)
    nameMap["river"] = 33
    v ,exist := nameMap["river"]
    if exist {
        fmt.Println("exist ",v)
    }

答案 11 :(得分:-15)

只需使用

if len(m) == 0 {
    ...
}