- 原文地址:Part 13: Maps
- 原文作者:Naveen R
- 譯者:咔嘰咔嘰 轉載請註明出處。
什麼是 map
map 是 Go 中的內建型別,它將值與鍵相關聯。可以使用相應的鍵查詢該值。
怎麼建立 map
可以指定鍵和值的型別,然後通過make
函式來建立一個 map,語法為make(map[type of key]type of value)
personSalary := make(map[string]int)
複製程式碼
上面的程式碼建立了一個叫personSalary
的 map,它的鍵的型別為string
,值的型別為int
。
map 的零值為nil
,如果你嘗試給空 map 增加元素,執行時將會觸發 panic,因此,必須使用make
函式初始化 map。
package main
import (
"fmt"
)
func main() {
var personSalary map[string]int
if personSalary == nil {
fmt.Println("map is nil. Going to make one.")
personSalary = make(map[string]int)
}
}
複製程式碼
在上述程式碼中,personSalary
是空的,所以必須用 make 函式初始化。該程式碼輸出map is nil. Going to make one.
給 map 增加元素
給 map 增加元素的語法和陣列一樣,下面的程式碼將給personSalary
增加新的元素。
package main
import (
"fmt"
)
func main() {
personSalary := make(map[string]int)
personSalary["steve"] = 12000
personSalary["jamie"] = 15000
personSalary["mike"] = 9000
fmt.Println("personSalary map contents:", personSalary)
}
複製程式碼
上面的程式將會輸出,personSalary map contents: map[steve:12000 jamie:15000 mike:9000]
map 也可以在初始化的時候新增元素,
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("personSalary map contents:", personSalary)
}
複製程式碼
上面的程式宣告瞭personSalary
,並在宣告過程中為它新增了兩個元素。之後又新增了一個鍵為mike
的元素。該程式輸出
personSalary map contents: map[steve:12000 jamie:15000 mike:9000]
複製程式碼
鍵的型別並不僅僅是string
。所有可比較的型別,如boolean
,integer
,float
,complex
,string
,...也可以是鍵。如果你想了解有關類似型別的更多資訊,請訪問http://golang.org/ref/spec#Comparison_operators
訪問 map 的元素
現在我們已經向 map 新增了一些元素,讓我們學習如何訪問它們。 map[key]
是訪問 map 元素的語法。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
employee := "jamie"
fmt.Println("Salary of", employee, "is", personSalary[employee])
}
複製程式碼
上述程式非常簡單。員工 Jamie 的工資被找到並列印出來。程式輸出Salary of jamie is 15000.
如果元素不存在會發生什麼?map 將返回該元素型別的零值。在personSalary
的例子中,如果我們嘗試訪問當前不存在的元素,則返回int
的零值 0。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
employee := "jamie"
fmt.Println("Salary of", employee, "is", personSalary[employee])
fmt.Println("Salary of joe is", personSalary["joe"])
}
複製程式碼
上面的程式將輸出,
Salary of jamie is 15000
Salary of joe is 0
複製程式碼
上面的程式返回了 joe 的工資為 0,我們並沒有得到 joe 不存在於personSalary
中的資訊。
如果我們想知道 map 中是否存在某個鍵,該怎麼辦?
value, ok := map[key]
複製程式碼
上面的語法就是找出 map 中是否存在某個鍵,如果ok
是true
的話,那就說明鍵存在,並且值為value
。否則ok
為false
,value
為空。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
newEmp := "joe"
value, ok := personSalary[newEmp]
if ok == true {
fmt.Println("Salary of", newEmp, "is", value)
} else {
fmt.Println(newEmp,"not found")
}
}
複製程式碼
上述程式的第 15 行,由於 joe 不存在,ok
為false
。因此程式輸出
joe not found
複製程式碼
使用range for
可以迭代所有的 map 元素。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("All items of a map")
for key, value := range personSalary {
fmt.Printf("personSalary[%s] = %d\n", key, value)
}
}
複製程式碼
上述程式輸出,
All items of a map
personSalary[mike] = 9000
personSalary[steve] = 12000
personSalary[jamie] = 15000
複製程式碼
一個重要的事實是,使用range for
迭代獲取元素的順序,並不能保證結果每次相同。
刪除元素
從 map 中刪除一個 key 的語法為delete(map, key)
,刪除函式不返回任何值。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("map before deletion", personSalary)
delete(personSalary, "steve")
fmt.Println("map after deletion", personSalary)
}
複製程式碼
上述程式刪除 key 為 steve 的元素,程式輸出
map before deletion map[steve:12000 jamie:15000 mike:9000]
map after deletion map[mike:9000 jamie:15000]
複製程式碼
map 的長度
可以使用len
函式確定 map 的長度。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("length is", len(personSalary))
}
複製程式碼
上述程式使用len(personSalary)
計算 map 的長度,輸出,length is 3
map 是指標傳遞
和 slice 一樣,map 也是指標傳遞的。將 map 賦值給新變數時,它們都指向相同的內部資料結構。因此修改一個會影響另外一個。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("Original person salary", personSalary)
newPersonSalary := personSalary
newPersonSalary["mike"] = 18000
fmt.Println("Person salary changed", personSalary)
}
複製程式碼
在上述程式碼的第 14 行,personSalary
賦值給newPersonSalary
。在下一行,mike 的工資被修改為 18000,personSalary
中的薪水也會變成 18000。程式輸出,
Original person salary map[steve:12000 jamie:15000 mike:9000]
Person salary changed map[steve:12000 jamie:15000 mike:18000]
複製程式碼
類似的,如果將 map 作為函式的接收者。當對函式內的 map 進行更改時,呼叫者將可以看到更改。
map 的等值比較
map 的等值比較不能使用==
操作符,==
操作符僅僅能用來檢查該 map 是否為nil
。
package main
func main() {
map1 := map[string]int{
"one": 1,
"two": 2,
}
map2 := map1
if map1 == map2 {
}
}
複製程式碼
上述的程式碼將會丟擲編譯錯誤,invalid operation: map1 == map2 (map can only be compared to nil).
檢查兩個 map 是否相等的方法是逐個比較每個元素是否一樣。為此編寫一個一個函式是一個不錯的方法:)