我知道可以使用以下方式遍历映射 m
:
for k, v := range m { ... }
查找键,但是否有更有效的方法来测试地图中的键是否存在?
我知道可以使用以下方式遍历映射 m
:
for k, v := range m { ... }
查找键,但是否有更有效的方法来测试地图中的键是否存在?
以下是如何检查一个映射是否包含某个键的方法。
val, ok := myMap["foo"]
// If the key exists
if ok {
// Do something
}
这段代码初始化了两个变量。如果映射中存在“foo”键,则val
的值为对应值,否则为“零值”(在此情况下为空字符串)。ok
是一个布尔型变量,如果键存在,则设置为true
。
如果需要,可以将其简化为一行。
if val, ok := myMap["foo"]; ok {
//do something here
}
在 Go 语言中,你可以在 if 语句的条件之前放置一个初始化语句(注意分号)。这样做的结果是,val
和 ok
的作用域将仅限于 if 语句的主体部分,在那里使用它们非常有帮助。
var val string = ""
会保持不变,而 val, ok :=
则会创建一个同名的新局部变量,只在该代码块中可见。 - OneOfOneif _, ok := dict["foo"]; ok { //在这里执行某些操作 }
- Emeka Augustine(x, err)
和(x, ok)
这两种形式有点令人困惑。 - BallpointBen尝试使用map中不存在的键检索值将返回map条目类型的零值。例如,如果map包含整数,则查找不存在的键将返回0。可以将集合实现为值类型为bool的map。将map条目设置为true以将值放入集合中,然后通过简单索引进行测试。
有时候你需要区分一个缺失的条目和零值。 "UTC"是否有条目,还是因为根本不在地图中而为0?你可以用一种多重赋值形式来区分它们。
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") }
var seconds int var ok bool seconds, ok = timeZone[tz]
由于显而易见的原因,这被称为“逗号 ok”惯用语。在这个例子中,如果 tz 存在,seconds 将被适当设置,ok 将为 true;如果不存在,seconds 将被设置为零,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]
在 go-nuts 邮件列表 进行搜索,找到了 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
语句,value
和ok
变量只在if
条件中可见。
_, ok := dict["baz"]; ok
。_
部分会舍弃值而不创建临时变量。 - Matthew Crumley_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
这里有一个在 Go Playground 中的例子。
根据Effective Go中的 Maps 部分:
如果使用一个不存在于 map 中的 key 获取 map 的值,将返回该 map 条目类型的零值。例如,如果 map 包含整数,则查找不存在的 key 将返回 0。
有时需要区分缺少条目和零值。对于“UTC”是否有条目,还是因为根本不在 map 中而是空字符串?您可以使用一种多重赋值的形式进行区分。
var seconds int
var ok bool
seconds, ok = timeZone[tz]
出于明显的原因,这被称为“comma ok”习语。在此示例中,如果存在tz,则将适当设置秒,并将ok设置为true;如果不存在,则将秒设置为零,并将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]
看一下这段代码片段
nameMap := make(map[string]int)
nameMap["river"] = 33
v ,exist := nameMap["river"]
if exist {
fmt.Println("exist ",v)
}
var d map[string]string
value, ok := d["key"]
if ok {
fmt.Println("Key Present ", value)
} else {
fmt.Println(" Key Not Present ")
}
如其他答案所述,通用解决方案是在特殊形式的赋值中使用索引表达式:
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
这是一个简洁明了的语句。但它有一些限制: 它必须是特定形式的赋值语句,右侧表达式只能是映射索引表达式,左侧表达式列表必须恰好包含两个操作数,第一个操作数的值类型可赋值,第二个操作数的值类型必须为bool
。此特殊形式的结果的第一个值将是与键相关联的值,第二个值将告诉是否实际上存在具有给定键的映射条目(如果该键存在于映射中)。如果左侧表达式列表中的一个结果不需要,则还可以包含空标识符。
重要的是要知道,如果索引映射值为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
类型的零值)存储到map中,我们也可以通过比较索引表达式的非特殊形式与零值来测试键是否在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
进行比较,可以测试键是否存在于映射中。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")
}
Contains 'one': true
'two' is in the set
'three' is not in the set
相关阅读:如何创建一个包含唯一字符串的数组?
var v, ok T = a[x]
中的 T
是什么?难道 ok
必须是布尔值吗? - Kokizzumap [bool] bool
且 T
是 bool
的情况下工作(编译),但如果地图类型是 map [interface{}] bool
且 T
是 interface {}
,那么它也可以工作;此外,它还可以使用具有 bool
作为基础类型的自定义类型,详见Go Playground。所以由于该形式适用于多个类型替换为 T
,因此使用了一般的 T
。ok
的类型可以是任何可以分配未命名的 bool
的东西。 - icza 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存在吗?是true。 不存在吗?是false。
_, ok = m["somestring"]
should be =_, ok := m["somestring"]
- Elroy Jetson这个提及在"索引表达式"下。
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
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")
}
}