Go 的 map 讀取不存在的 key 會回傳 zero value
讀一個不存在的 key 不會報錯、也不會回傳 nil,而是回傳 value 型別的 zero value。所以
m["nobody"]得到0時,你分不出是「沒有這個人」還是「這個人的值就是 0」。
scores := map[string]int{"Amy": 0}
scores["Amy"] // 0 ← 有這個 key,值就是 0
scores["Nobody"] // 0 ← 沒有這個 keycomma ok:多接一個 bool 來分辨
v, ok := scores["Nobody"]
// ↑ ↑
// 值 這個 key 存在嗎前面是 value,後面是 bool——兩個不同的東西,別接反:
v, ok := scores["Amy"] // v=0, ok=true ← key 在,值真的是 0
v, ok := scores["Nobody"] // v=0, ok=false ← key 不在兩次 v 都是 0,靠 ok 才分得出差別。慣用寫法是塞進 if 的初始化陳述句裡:
if v, ok := scores["Amy"]; ok {
fmt.Println(v) // 只有 key 真的存在才進來
}ok 的型別永遠是 bool,跟 map 的 value 型別無關:
names := map[int]string{}
s, ok := names[1] // s = ""(string 的 zero value),ok = false這不是函式回傳,是語言內建的語法
map 索引式在「接兩個變數」的位置時,編譯器會多給一個 bool。同一個運算式接一個或接兩個都合法:
v := scores["Amy"] // 接一個:只給值
v, ok := scores["Amy"] // 接兩個:值 + 存在與否同樣的 comma ok 形式在 channel 接收(v, ok := <-ch)與 type assertion(v, ok := x.(int))也有,是語言層級的慣例而不是 map 專屬。
而 if ok 之所以能寫,正是因為它本來就是 bool——Go 沒有 truthy/falsy,如果 ok 接到的是 value,if ok 根本編譯不過。
「讀取永遠有答案、不需要碰到任何記憶體」也是為什麼 nil map 可以讀。