正如其他答案所指出的,一般的解决方案是在特殊形式的assignment 中使用index expression:
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
在使用不存在的键进行索引时获取值类型的零值也允许我们将具有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
查看相关:How can I create an array that contains unique strings?