iT邦幫忙

2022 iThome 鐵人賽

DAY 17
0
自我挑戰組

跟著 Go 實戰聖經 一起自學 Go系列 第 17

DAY 17 Go 語言 的複合型別 - 映射表 (map)

  • 分享至 

  • xImage
  •  

昨天介紹完切片 (slice) 不同的複製方式與隱藏陣列的關聯,今天繼續來介紹有點類似的映射表 (map) 吧!

map 是什麼以及怎麼取得 map 內元素

Go 語言的 map 是一種雜湊表 (hashmap) ,在陣列及切片中,我們如果需要找到元素值或是更換元素值時,都可以使用索引,那是因為陣列及切片是有序集合,索引值一定從 0 起算且每次皆加一,但這個索引鍵跟元素值資料並沒有直接關聯; 但在映射表 (map) 中就不是如此,索引鍵 (key) 本身也是資料的一部份,且可以對應到元素值 (value) 。
索引鍵 (key) 可以是任意型別,但不能是切片,因為切片與切片不能相互比較 ; 而元素值 (value) 就真的可以是任意型別,無論陣列、切片、或是另一個 map 都是可以的。
至於如何取得 map 內元素,其實跟陣列切片異曲同工之妙,使用中括號在之中填入要取得的索引鍵 (key),如: [key]
補充:
正常來說有序資料建議放在陣列或是切片,因為當我們使用 for range 迴圈走訪 map 時,會將資料順序打亂,這時即便你將索引鍵 (key) 按照順序排列,也還是難逃被打亂的命運 ( for range 迴圈詳細可見 DAY 10 ) 。

定義 map 與新增 map 元素值

定義 map

map[<key 型別>]<value 型別>

在 Go 語言中 map 不會幫我們初始化,且 map 的零值就是 nil ,所以當我們定義 map 時,需要一併賦予其 索引鍵 (key)元素值 (value) ; 如果硬要對於一個沒有初始化的 map 賦值,執行時會引發 Go 語言中的 panic (之後章節會詳細介紹),我先簡單將其理解為 panic 會將函式的流程中斷,所以 不建議定義一個未經初始化 (都是零值 nil ) 的 map。

定義 map 且賦予其索引鍵 (key) 跟元素值 (value)

map[<key 型別>]<value 型別>{<key 1>:<value 1>, <key 2>:<value 2>, ..., <key N>:<value N>}

使用 make() 定義一個初始化的 map

跟切片一樣,我們也可以使用內建函式 make() 來定義一個初始化的 map :

make(map[<key 型別>]<value 型別>, <容量>)

與跟切片的 make() 函式不同之處在於,我們不需要給 make() 指定特定長度,因為 Go 語言不會給用 make() 定義的 map 索引鍵 key , map 的容量是可填也可以省略的,若想查詢 map 的容量,我們應該選擇 len(),而不是cap(),因為 cap 是返回切片的容量,並不適用在 map 。

補充:
map 跟切片一樣,若將一個 map 複製,而舊 map 與新 map 是指向同一個底層資料,為了避免又發生我們不曉得指向同一個 map 的問題,建議可以使用迴圈走訪 map 將 key 與 value 寫進新的 map。

對 map 加入新的元素

當 map 初始化完,想要將其加入新的 key 與 value 是使用 [] ,且不用擔心長度問題,想新增就新增。

<map 名稱>[<索引的 key>] = <value>

範例 1:

package main

import "fmt"

func main(){
    myFavorite := map[string]string{ // 定義一個 map ,且賦予其索引鍵 (key) 跟元素值 (value)來初始化 map
        "fruit":"mango",
        "animal":"panda",
        "dessert":"cheesecake",
    }
    myFavorite["weather"] = "sunny" // 使用 [] 加入要新增進 map 的 key 與 value

    fmt.Println("myFavorite",myFavorite)
    
    for key, value := range myFavorite{
        fmt.Println("key:",key," = value:",value) // 將 key 與 value 一一印出來
    }
}

範例 1(執行結果):

myFavorite map[animal:panda dessert:cheesecake fruit:mango weather:sunny]
key: fruit  = value: mango
key: animal  = value: panda
key: dessert  = value: cheesecake
key: weather  = value: sunny

從 map 讀取元素值

若要從 map 裡取用 value 時,需要使用索引值 key 在 map 中取用資料,若是該索引值 key 不存在, Go 語言會回傳該 map 資料型別的零值,所以有時後我們也可以透過回傳的零值來判斷該索引機是否存在,但特別注意的是這並不一定是完全正確的,因為我們也可以自己將索引值 value 設為該型別的零值,也就是說它可以是代表有意義的零值資料。
至於要怎麼分辨零值資料的索引值 key 是不是真的存在,可以在 map 多接收一個參數 存在狀態,存在狀態是一個布林值,如果 map 含有當個 key ,存在狀態就會是 true ,反之為 false。

<值>, <存在狀態> := <map 名稱>[<索引鍵>]

範例 2:

package main

import (
	"fmt"
)

func main() {
    myFavorite := map[string]string{ // 定義一個 map ,且賦予其索引鍵 (key) 跟元素值 (value)來初始化 map
        "fruit":"mango",
        "animal":"panda",
        "dessert":"cheesecake",
    }
    favoriteTitle, exists := myFavorite["fruit"] // 讀取 myFavorite 這個 map 的 key 值 fruit 的 value
    if exists {  // 如果 fruit 這個 key 有相對應的 value
        fmt.Println("目前列表:")
        for key, value := range myFavorite { // 用 for range 走訪
            fmt.Println("key:",key," = value:",value)
        }
    }else{
        fmt.Println("查無此品項",favoriteTitle)
    }
    fmt.Println("查詢品項:",favoriteTitle)
}

範例 2(執行結果):

目前列表:
key: fruit  = value: mango
key: animal  = value: panda
key: dessert  = value: cheesecake
查詢品項: mango

從 map 刪除元素值

在 Go 語言的複合型別中,陣列因為長度固定,故元素不可刪除,只能將其設為零值 ; 在切片中,一樣可以將元素設為零值,或是使用 append() 創造擷取新的一段切片 ; 在 map 中即便你將元素值改為零值,該元素依然存在,且也無法使用 append() 來製造新的 map ,所以若要刪除 map 元素值,需要使用 Go 語言內建 delete() 函式,且。delete() 函式是沒有回傳值的,如果不小心刪除到不存在的索引值,也不會有問題或是報錯,最後 delete() 函式只能搭配 map ,不能搭配陣列或切片。

delete(<map 名稱>, <索引鍵>)
package main

import (
	"fmt"
)

var myFavorites = map[string]string {
    "fruit":"mango",
    "animal":"panda",
    "dessert":"cheesecake",
    "weather":"sunny",
}

func delleteMyFavorite(title string)() {
    delete(myFavorites,title)
}

func main() {
    favoriteTitle := myFavorites["fruit"]
    delleteMyFavorite(favoriteTitle)
    
    fmt.Println("我的最愛:",myFavorites)
}
我的最愛: map[animal:panda dessert:cheesecake fruit:mango weather:sunny]

今天介紹了 Go 語言 的複合型別映射表 (map) 的所有用法,那我們明天繼續學習如何自訂型別,以及在 Go 語言中結構 (struct) 是什麼,明天見!


上一篇
DAY 16 Go 語言 的複合型別 - 切片 (slice) 不同的複製方式與隱藏陣列的關聯
下一篇
DAY 18 Go 語言 自訂型別 (custom types) 及結構 (struct) 的定義
系列文
跟著 Go 實戰聖經 一起自學 Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言