前言
在上一篇文章中,我們介紹了兩個線性的容器:陣列和切片,這兩個容器皆以數字為索引。在本文中,我們會介紹映射 (map),這是另外一種容器;映射儲存鍵/值 (key/value) 對,可以用數種資料型別做為鍵,取得相對應的值。
註:map 有些教材不翻,也有些教材翻成映射,本文取後者;相同的概念可見於 Python 的字典 (dictionary)、Perl 的雜湊 (hash) 和 PHP 的關連性陣列 (associative array) 等。
建立映射
以下實例建立一個以字串為鍵、以字串為值的映射,接著檢查某組鍵值對是否存在:
package main
import (
"log"
)
func main() {
// Declare an empty map.
m := make(map[string]string)
// Insert key/value pairs
m["Go"] = "Beego"
m["Python"] = "Django"
m["Ruby"] = "Rails"
m["PHP"] = "Laravel"
// Call the value by the key.
if !(m["Go"] == "Beego") {
log.Fatal("Wrong value")
}
}
檢查鍵值對是否為空
如果鍵/值對不存在,會依映射的值的型別回傳預設值。在此例中,回傳空字串:
package main
import (
"log"
)
func main() {
m := make(map[string]string)
m["Go"] = "Beego"
m["Python"] = "Django"
m["Ruby"] = "Rails"
m["PHP"] = "Laravel"
// No such key/value pair.
if !(m["Java"] == "") {
log.Fatal("Wrong value")
}
}
如果不確定鍵/值對是否存在,可以用以下語法檢查:
package main
import (
"log"
)
func main() {
m := make(map[string]string)
m["Go"] = "Beego"
m["Python"] = "Django"
m["Ruby"] = "Rails"
m["PHP"] = "Laravel"
v, ok := m["Go"]
if !ok {
log.Fatal("It should be true")
}
if !(v == "Beego") {
log.Fatal("Wrong value")
}
_, ok = m["Java"]
if !(ok == false) {
log.Fatal("It should be false")
}
}
移除鍵值對
我們也可以用 delete
函式去除鍵/值對:
package main
import (
"log"
)
func main() {
m := make(map[string]string)
m["Go"] = "Beego"
m["Python"] = "Django"
m["Ruby"] = "Rails"
m["PHP"] = "Laravel"
_, ok := m["PHP"]
if !ok {
log.Fatal("It should exist")
}
// Remove the key/value pair.
delete(m, "PHP")
_, ok = m["PHP"]
if !(ok == false) {
log.Fatal("It should not exist")
}
}
映射的鍵/值對是單向的,我們僅能由鍵得到值,但不能由值得到鍵;另外,鍵不能重覆,但值可以。
走訪映射
類似於陣列和切片,我們也可以用迭代器走訪映射:
package main
import (
"fmt"
)
func main() {
m := make(map[string]string)
m["Go"] = "Beego"
m["Python"] = "Django"
m["Ruby"] = "Rails"
m["PHP"] = "Laravel"
for k, v := range m {
fmt.Println(fmt.Sprintf("%s: %s", k, v))
}
}
要注意的是,映射是無序的,我們多執行幾次,就會發現每次的順序都不一樣,見下例:
package main
import (
"fmt"
)
func main() {
m := make(map[string]string)
m["Go"] = "Beego"
m["Python"] = "Django"
m["Ruby"] = "Rails"
m["PHP"] = "Laravel"
for i := 0; i < 10; i++ {
for k, v := range m {
fmt.Println(fmt.Sprintf("%s: %s", k, v))
}
fmt.Println("")
}
}
如果想要保持鍵/值對的順序,我們要額外儲存鍵在一個切片中,見下例:
package main
import "fmt"
func main() {
// Create an anomynous struct.
data := struct {
m map[string]string
order []string
}{
m: make(map[string]string),
order: []string{},
}
// Insert several key/value pairs.
data.m["Go"] = "Beego"
data.order = append(data.order, "Go")
data.m["Python"] = "Django"
data.order = append(data.order, "Python")
data.m["Ruby"] = "Rails"
data.order = append(data.order, "Ruby")
data.m["PHP"] = "Laravel"
data.order = append(data.order, "PHP")
// Iterate these key/value pairs with order.
for _, e := range data.order {
fmt.Println(fmt.Sprintf("%s: %s", e, data.m[e]))
}
}
在本例中,我們用一個結構體一併儲存映射和切片。我們會在後文介紹結構體。
結語
藉由本文的介紹,相信各位讀者可以知道映射如何使用。由於映射相當實用,各位讀者可以多多練習,以熟悉映射的使用方式。