我知道我可以遍历映射m
for k, v := range m { ... }
寻找一个键,但是有没有更有效的方法来测试一个键在地图中的存在呢?
我知道我可以遍历映射m
for k, v := range m { ... }
寻找一个键,但是有没有更有效的方法来测试一个键在地图中的存在呢?
当前回答
正如其他答案所指出的,一般的解决方案是在特殊形式的赋值中使用索引表达式:
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
This is nice and clean. It has some restrictions though: it must be an assignment of special form. Right-hand side expression must be the map index expression only, and the left-hand expression list must contain exactly 2 operands, first to which the value type is assignable, and a second to which a bool value is assignable. The first value of the result of this special form will be the value associated with the key, and the second value will tell if there is actually an entry in the map with the given key (if the key exists in the map). The left-hand side expression list may also contain the blank identifier if one of the results is not needed.
重要的是要知道,如果索引映射值为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
在Go Playground上试试。
如果我们知道在地图中不使用0值,我们可以利用这个。
例如,如果值类型是字符串,并且我们知道我们从来没有在map中存储值为空字符串的条目(字符串类型为零值),我们也可以通过比较索引表达式(结果)的非特殊形式与零值来测试键是否在映射中:
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”形式做到这一点)。更多信息:在一个条件下,检查key是否存在于多个映射中
在索引不存在的键时获取值类型的零值还允许我们方便地将bool值作为集合使用。例如:
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")
}
它输出(在Go Playground上试试):
Contains 'one': true
'two' is in the set
'three' is not in the set
请参阅相关:如何创建包含唯一字符串的数组?
其他回答
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)
然后,去查地图,去 somestring存在吗?真正的 不存在?假
在“索引表达式”中提到。
赋值中使用的map[K]V类型映射a上的索引表达式 或者初始化特殊形式 V, ok = a[x] V, ok:= a[x] Var v, ok = a[x] 产生一个额外的无类型布尔值。ok的值为true,如果 键x存在于映射中,否则为false。
看看这段代码片段
nameMap := make(map[string]int)
nameMap["river"] = 33
v ,exist := nameMap["river"]
if exist {
fmt.Println("exist ",v)
}
除了《Go编程语言规范》,你还应该阅读《Effective Go》。在地图的部分,他们说,除了别的以外:
An attempt to fetch a map value with a key that is not present in the map will return the zero value for the type of the entries in the map. For instance, if the map contains integers, looking up a non-existent key will return 0. A set can be implemented as a map with value type bool. Set the map entry to true to put the value in the set, and then test it by simple indexing. 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") } Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that 0 because it's not in the map at all? You can discriminate with a form of multiple assignment. var seconds int var ok bool seconds, ok = timeZone[tz] For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false. Here's a function that puts it together with a nice error report: func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 } To test for presence in the map without worrying about the actual value, you can use the blank identifier (_) in place of the usual variable for the value. _, present := timeZone[tz]
var d map[string]string
value, ok := d["key"]
if ok {
fmt.Println("Key Present ", value)
} else {
fmt.Println(" Key Not Present ")
}