我知道我可以迭代一张地图,
对于k,v:=范围m {…}
并寻找一个键,但有一种更有效的方法来测试一个键在地图中的存在吗?
我无法在局域网中找到答案……
搜索了 疯狂的电子邮件列表 并找到了Peter Froehlich在11/15/2009发布的解决方案。
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 变量只在内部可见 if 条件。
if
value
ok
它在下面提到 “索引表达式” 。
分配中使用的类型map [K] V的映射a上的索引表达式 或初始化特殊形式 v, ok = a[x] v, ok := a[x] var v, ok = a[x] 产生一个额外的无类型布尔值。如果是,则ok的值为true 键x出现在地图中,否则为false。
分配中使用的类型map [K] V的映射a上的索引表达式 或初始化特殊形式
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
产生一个额外的无类型布尔值。如果是,则ok的值为true 键x出现在地图中,否则为false。
一行答案:
if val, ok := dict["foo"]; ok { //do something here }
if Go中的语句可以包括条件和初始化语句。上面的例子同时使用:
初始化两个变量 - val 将从地图中接收“foo”的值或“零值”(在本例中为空字符串)和 ok 将收到一个将被设置为的bool true 如果“foo”实际存在于地图中
val
true
评估板 ok ,这将是 true 如果“foo”在地图中
如果“foo”确实存在于地图中,那么身体就会出现 if 声明将被执行并且 val 将是该范围的本地。
的 编辑: 强> 以下答案在Go 1之前。从Go 1开始,它不再准确/有效。
此外 Go编程语言规范 ,你应该读 有效的去 。在章节中 地图 他们说,除其他外:
“尝试使用地图中不存在的键获取地图值将导致程序崩溃,但有一种方法可以安全地使用多次分配。”
var seconds int var ok bool seconds, ok = 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个操作数,第一个值类型可赋值,第二个操作数为 bool 值是可分配的。此特殊表单索引表达式的结果的第一个值将是与键关联的值,第二个值将指示映射中是否存在具有给定键的条目(如果键存在于映射中)。左侧表达式列表也可以包含 空白标识符 如果不需要其中一个结果。
bool
重要的是要知道索引的映射值是否为 nil 或者不包含密钥,索引表达式的计算结果为 零价值 地图的值类型。例如:
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
试试吧 去游乐场 。
因此,如果我们知道我们不在地图中使用零值,我们就可以利用这一点。
例如,如果值类型是 string ,我们知道我们永远不会在地图中存储值为空字符串的条目(零值为 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] != "")
输出(试试吧 去游乐场 ):
Key 0 exists: true Key 1 exists: true Key 2 exists: false
在实践中,在很多情况下我们不将零值值存储在地图中,因此可以经常使用。例如,接口和函数类型的值为零 nil ,我们经常不存储在地图中。因此,测试一个键是否在地图中可以通过比较它来实现 nil 。
使用这种“技术”还有另一个优点:您可以以紧凑的方式检查多个键的存在(您不能使用特殊的“逗号确定”形式)。更多关于此: 检查一个条件下多个映射中是否存在密钥
两个值赋值可用于此目的。请查看下面的示例程序
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") } }
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存在?真正 不存在?假
_, exists := timeZone[tz] // Just checks for key existence val, exists := timeZone[tz] // Checks for key existence and retrieves the value
这是一个 Go Playground的例子 。
每个 地图 部分 有效的去 :
尝试使用地图中不存在的键获取地图值将返回地图中条目类型的零值。例如,如果地图包含整数,则查找不存在的键将返回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]
尝试使用地图中不存在的键获取地图值将返回地图中条目类型的零值。例如,如果地图包含整数,则查找不存在的键将返回0。
有时您需要将缺失的条目与零值区分开来。是否有“UTC”的条目,或者是空字符串,因为它根本不在地图中?您可以区分多种分配形式。
由于显而易见的原因,这被称为“逗号确定”成语。在这个例子中,如果存在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 }
要测试地图中的状态而不必担心实际值,可以使用空白标识符(_)代替值的常用变量。
这里更好的方式
if _, ok := dict["foo"]; ok { //do something here }
只是用
if len(m) == 0 { ... }