這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。歡迎來到 [Golang 系列教程](/subject/2)的第 13 個教程。 ## 什麼是 map ?map 是在 Go 中將值(value)與鍵(key)關聯的內建類型。通過相應的鍵可以擷取到值。## 如何建立 map ?通過向 `make` 函數傳入鍵和值的類型,可以建立 map。`make(map[type of key]type of value)` 是建立 map 的文法。```gopersonSalary := make(map[string]int)```上面的代碼建立了一個名為 `personSalary` 的 map,其中鍵是 string 類型,而值是 int 類型。map 的零值是 `nil`。如果你想添加元素到 nil map 中,會觸發運行時 panic。因此 map 必須使用 `make` 函數初始化。```gopackage mainimport ("fmt")func main() { var personSalary map[string]intif personSalary == nil {fmt.Println("map is nil. Going to make one.")personSalary = make(map[string]int)}}```[線上運行程式](https://play.golang.org/p/IwJnXMGc1M)上面的程式中,personSalary 是 nil,因此需要使用 make 方法初始化,程式將輸出 `map is nil. Going to make one.`。## 給 map 添加元素給 map 添加新元素的文法和數組相同。下面的程式給 `personSalary` map 添加了幾個新元素。```gopackage mainimport ("fmt")func main() {personSalary := make(map[string]int)personSalary["steve"] = 12000personSalary["jamie"] = 15000personSalary["mike"] = 9000fmt.Println("personSalary map contents:", personSalary)}```[線上運行程式](https://play.golang.org/p/V1lnQ4Igw1)上面的程式輸出:`personSalary map contents: map[steve:12000 jamie:15000 mike:9000]`你也可以在聲明的時候初始化 map。```gopackage mainimport ( "fmt")func main() { personSalary := map[string]int {"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000fmt.Println("personSalary map contents:", personSalary)}```[線上運行程式](https://play.golang.org/p/nlH_ADhO9f)上面的程式聲明了 personSalary,並在聲明的同時添加兩個元素。之後又添加了鍵 `mike`。程式輸出:```personSalary map contents: map[steve:12000 jamie:15000 mike:9000]```鍵不一定只能是 string 類型。所有可比較的類型,如 boolean,interger,float,complex,string 等,都可以作為鍵。關於可比較的類型,如果你想瞭解更多,請訪問 [http://golang.org/ref/spec#Comparison_operators](http://golang.org/ref/spec#Comparison_operators)。## 擷取 map 中的元素目前我們已經給 map 添加了幾個元素,現在學習下如何擷取它們。擷取 map 元素的文法是 `map[key]` 。```gopackage mainimport ("fmt")func main() {personSalary := map[string]int{"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000employee := "jamie"fmt.Println("Salary of", employee, "is", personSalary[employee])}```[線上運行程式](https://play.golang.org/p/-TSBac7F1v)上面的程式很簡單。擷取並列印員工 `jamie` 的薪資。程式輸出 `Salary of jamie is 15000`。如果擷取一個不存在的元素,會發生什麼呢?map 會返回該元素類型的零值。在 `personSalary` 這個 map 裡,如果我們擷取一個不存在的元素,會返回 `int` 類型的零值 `0`。```gopackage mainimport ( "fmt")func main() {personSalary := map[string]int{"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000employee := "jamie"fmt.Println("Salary of", employee, "is", personSalary[employee])fmt.Println("Salary of joe is", personSalary["joe"])}```[線上運行程式](https://play.golang.org/p/EhUJhIkYJU)上面程式輸出:```Salary of jamie is 15000Salary of joe is 0```上面程式返回 `joe` 的薪資是 0。`personSalary` 中不包含 `joe` 的情況下我們不會擷取到任何執行階段錯誤。如果我們想知道 map 中到底是不是存在這個 `key`,該怎麼做:```govalue, ok := map[key]```上面就是擷取 map 中某個 key 是否存在的文法。如果 `ok` 是 true,表示 key 存在,key 對應的值就是 `value` ,反之表示 key 不存在。```gopackage mainimport ("fmt")func main() {personSalary := map[string]int{"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000newEmp := "joe"value, ok := personSalary[newEmp]if ok == true {fmt.Println("Salary of", newEmp, "is", value)} else {fmt.Println(newEmp,"not found")}}```[線上運行程式](https://play.golang.org/p/q8fL6MeVZs)上面的程式中,第 15 行,`joe` 不存在,所以 `ok` 是 false。程式將輸出:```joe not found```遍曆 map 中所有的元素需要用 `for range` 迴圈。```gopackage mainimport ("fmt")func main() {personSalary := map[string]int{"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000fmt.Println("All items of a map")for key, value := range personSalary {fmt.Printf("personSalary[%s] = %d\n", key, value)}}```[線上運行程式](https://play.golang.org/p/gq9ZOKsI9b)上面程式輸出:```All items of a mappersonSalary[mike] = 9000personSalary[steve] = 12000personSalary[jamie] = 15000``` __有一點很重要,當使用 `for range` 遍曆 map 時,不保證每次執行程式擷取的元素順序相同。__## 刪除 map 中的元素刪除 `map` 中 `key` 的文法是 [_delete(map, key)_](https://golang.org/pkg/builtin/#delete)。這個函數沒有傳回值。```gopackage mainimport ( "fmt")func main() { personSalary := map[string]int{"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000fmt.Println("map before deletion", personSalary)delete(personSalary, "steve")fmt.Println("map after deletion", personSalary)}```[線上運行程式](https://play.golang.org/p/nroJzeF-a7)上述程式刪除了鍵 "steve",輸出:```map before deletion map[steve:12000 jamie:15000 mike:9000]map after deletion map[mike:9000 jamie:15000]```## 擷取 map 的長度擷取 map 的長度使用 [len](https://golang.org/pkg/builtin/#len) 函數。```gopackage mainimport ("fmt")func main() {personSalary := map[string]int{"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000fmt.Println("length is", len(personSalary))}```[線上運行程式](https://play.golang.org/p/8O1WnKUuDP)上述程式中的 _len(personSalary)_ 函數擷取了 map 的長度。程式輸出 `length is 3`。## Map 是參考型別和 [slices](https://golangbot.com/arrays-and-slices/) 類似,map 也是參考型別。當 map 被賦值為一個新變數的時候,它們指向同一個內部資料結構。因此,改變其中一個變數,就會影響到另一變數。```gopackage mainimport ("fmt")func main() {personSalary := map[string]int{"steve": 12000,"jamie": 15000,}personSalary["mike"] = 9000fmt.Println("Original person salary", personSalary)newPersonSalary := personSalarynewPersonSalary["mike"] = 18000fmt.Println("Person salary changed", personSalary)}```[線上運行程式](https://play.golang.org/p/OGFl3addq1)上面程式中的第 14 行,`personSalary` 被賦值給 `newPersonSalary`。下一行 ,`newPersonSalary` 中 `mike` 的薪資變成了 `18000` 。`personSalary` 中 `Mike` 的薪資也會變成 `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`。```gopackage mainfunc main() {map1 := map[string]int{"one": 1,"two": 2,}map2 := map1if map1 == map2 {}}```[線上運行程式](https://play.golang.org/p/MALqDyWkcT)上面程式拋出編譯錯誤 **invalid operation: map1 == map2 (map can only be compared to nil)**。判斷兩個 map 是否相等的方法是遍曆比較兩個 map 中的每個元素。我建議你寫一段這樣的程式實現這個功能 :)。我在一個程式裡實現了我們討論過的所有概念。你可以從 [github](https://github.com/golangbot/maps) 下載代碼。這就是 map 。謝謝你的閱讀。祝好。**上一教程 - [可變參數函數](https://studygolang.com/articles/12173)****下一教程 - [字串](https://studygolang.com/articles/12261)**
via: https://golangbot.com/maps/
作者:Nick Coghlan 譯者:ArisAries 校對:Noluye
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
3170 次點擊