代码之家  ›  专栏  ›  技术社区  ›  grokus

如何检查地图是否包含一个键在Go中?

  •  537
  • grokus  · 技术社区  · 15 年前

    我知道我可以迭代地图 m 通过,

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

    寻找一把钥匙,但是有没有一种更有效的方法来测试一把钥匙在地图上的存在?

    我找不到答案 language spec .

    10 回复  |  直到 6 年前
        1
  •  1012
  •   Kevin Burke    10 年前

    一行回答:

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

    说明:

    if go中的语句可以同时包含条件和初始化语句。上面的示例同时使用这两种方法:

    • 初始化两个变量- val 将从映射中接收“foo”值或“零值”(在本例中为空字符串)以及 ok 将收到一个设置为 true 如果“foo”真的出现在地图上

    • 评价 好啊 ,这将是 如果“foo”在地图上

    如果“foo”确实存在于地图中,则 如果 声明将被执行并且 瓦尔 将是该范围的本地。

        2
  •  91
  •   icza    8 年前

    编辑: 以下答案在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]
    
        3
  •  41
  •   grokus    15 年前

    搜查 go-nuts email list 并在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 声明, value ok 变量仅在 如果 条件。

        4
  •  18
  •   Matthew Rankin val    9 年前

    简短回答

    _, 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 .

    更长的答案

    每个 Maps 截面 Effective Go :

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

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

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

    由于明显的原因,这被称为__逗号ok_习语。在本例中,如果存在Tz,则秒数将被适当设置,OK为真;否则,秒数将被设置为零,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]
    
        5
  •  9
  •   Community kfsone    7 年前

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

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

    这个又漂亮又干净。但是它有一些限制:它必须是一个特殊形式的分配。右侧表达式只能是映射索引表达式,左侧表达式列表必须正好包含两个操作数,第一个操作数是值类型可赋值的,第二个操作数是 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 我们知道,我们从不在映射中存储值为空字符串的条目(对于 一串 类型),我们还可以通过将(索引表达式的结果)的非特殊形式与零值进行比较来测试键是否在映射中:

    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
    

    在实践中,有很多情况下,我们不在地图中存储零值,所以这可以经常使用。例如,接口和函数类型的值为零 ,我们通常不在地图中存储。因此,可以通过将密钥与 .

    使用这种“技术”还有另一个优点:您可以用一种简洁的方式检查多个键的存在(您不能用特殊的“逗号确定”形式来检查)。有关此的详细信息: Check if key exists in multiple maps in one condition

        6
  •  6
  •   Amazingandyyy    7 年前

    更好的方法

    if _, ok := dict["foo"]; ok {
        //do something here
    }
    
        7
  •  4
  •   mroman    6 年前

    下面提到 "Index expressions" .

    在赋值中使用的map[k]v类型的map a上的索引表达式。 或特殊窗体的初始化

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

    生成一个额外的非类型化布尔值。如果 键x存在于映射中,否则为false。

        8
  •  3
  •   Lady_Exotel    9 年前
        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)
    

    然后,去运行地图。 是否存在字符串?真 不存在?假

        9
  •  1
  •   Fathah Rehman P    6 年前

    为此,可以使用双值分配。请检查下面的示例程序

    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")
        }
    }
    
        10
  •  -14
  •   ketan    9 年前

    只使用

    if len(m) == 0 {
        ...
    }
    
    推荐文章