初學 Golang 30 天 - (9)Map

Go 這麼新語言,怎麼能沒有一個類似 JSON 陣列的方法、型態呢?這種鍵值的資料型態很方便閱讀的,當初設計的時候怎麼可能沒想到呢?在 Go 語言中你可以使用 Map!

Map

怎麼建立一個簡單的 Map 呢?

var x map[string]int

跟 Array 還有 Slice 有點相似對吧?我這邊說明一下 x 是變數名稱,map 這個是建立 Map 的時候用的關鍵詞彙不能省略,而括弧中的 string 表示鍵的型態,int 則是值的型態。
我們來嘗試建立看看一個 Map

var x map[string]int
x["key"] = 10
fmt.Println(x)

什麼!?居然出現 Panic,這個是什麼?

panic: runtime error: assignment to entry in nil map

我稍微省略了一些錯誤的 log ,讓我們聚焦在最重要的這一句話上面,他的意思是說不能賦予值到 nil map 上面。原來我們用 var x map[string]int 建立 Map 的時候沒有初始化它,所以它會建立一個 nil map,而 nil map 不能使用鍵,所以導致這樣的錯誤,那初始化怎麼寫呢?

x := make(map[string]int)
x["key"] = 10
fmt.Println(x)

如果你只是要印出鍵的數值。

x := make(map[string]int)
x["key"] = 10
fmt.Println(x["key"])

當然 string 不是唯一的選項,你也可以用 int 。

x := make(map[int]int)
x[1] = 10
fmt.Println(x[1])

這樣就可以使用數字當作鍵來用。
另外可以新增,但是要怎麼刪除呢? Go 有內建函式可以使用:

delete(x, 1)

除了新增刪除,如果今天我想要知道 map 有多少元素呢?
我們之前介紹過得 len() 也可以用的喔,如果只是剛建立沒有給值會是 0 ,如果像是前面的 x[1] = 10 這樣賦予值就會變成 1,以此類推。

len(x)

範例
簡單使用了建立 map 的操作和刪除的操作
http://play.golang.org/p/dKV3Tsl0d5
我們再來看另外一個範例

package main

import "fmt"

func main() {
    elements := make(map[string]string)
    elements["H"] = "Hydrogen"
    elements["He"] = "Helium"
    elements["Li"] = "Lithium"
    elements["Be"] = "Beryllium"
    elements["B"] = "Boron"
    elements["C"] = "Carbon"
    elements["N"] = "Nitrogen"
    elements["O"] = "Oxygen"
    elements["F"] = "Fluorine"
    elements["Ne"] = "Neon"
    
    fmt.Println(elements["Li"])
}

這邊是一列元素的縮寫和完整名稱,如果我們今天印出上面沒有宣告的呢?例如

fmt.Println(elements["Al"])

通常我們要印出不存在的,在編譯的時候會報錯,但是這邊你執行後你會發現 Map 不會。
那 Go 有沒有方法可以判斷它是否是空的呢?當然有的!

name, ok := elements["Al"]
fmt.Println(name, ok)

這樣會印出什麼呢?它會印出 false,因為他是空值,但是你會發現明明 map 就回傳兩個返回值,為什麼印出來只有 false?原因是 name 其實對應到 value,但是值是空值,所以就沒有印了,而 ok 是返回它有沒有值。
我們再來利用這個語法來做點進階的應用

if name, ok := elements["Al"]; ok {    
    fmt.Println(name, ok)
}

這裡的意思是說「Al 是否有值呢?如果有的話請印出」。
如果覺得前面初始化的太長了,你可以試試這種簡短的寫法:

elements := map[string]string{
    "H": "Hydrogen",
    "He": "Helium",
    "Li": "Lithium",
    "Be": "Beryllium",
    "B": "Boron",
    "C": "Carbon",
    "N": "Nitrogen",
    "O": "Oxygen",
    "F": "Fluorine",
    "Ne": "Neon",
}

當然我們都知道 JSON 格式可以是巢狀的,Go 當然一定也可以囉!
但是要怎麼做呢?

func main() {
    elements := map[string]map[string]string{
        "H": map[string]string{
            "name":"Hydrogen", 
            "state":"gas",
        },
        "He": map[string]string{
            "name":"Helium", 
            "state":"gas",
        },
        "Li": map[string]string{
            "name":"Lithium", 
            "state":"solid",
        },
        "Be": map[string]string{
            "name":"Beryllium", 
            "state":"solid",
        },
        "B":  map[string]string{
            "name":"Boron",
            "state":"solid",
        },
        "C":  map[string]string{
            "name":"Carbon",
            "state":"solid",
        },
        "N":  map[string]string{
            "name":"Nitrogen",
            "state":"gas",
        },
        "O":  map[string]string{
            "name":"Oxygen",
            "state":"gas",
        },
        "F":  map[string]string{
            "name":"Fluorine",
            "state":"gas",
        },
        "Ne":  map[string]string{
            "name":"Neon",
            "state":"gas",
        },
    }

    if el, ok := elements["Li"]; ok {    
        fmt.Println(el["name"], el["state"])
    }
}

本文章部份內容修改自 CC3.0 授權的 An Introduction to Programming in Go

comments powered by Disqus