練習 - 使用對應

已完成

Go 中的對應基本上是雜湊表,其為機碼和值組的集合。 對應中的所有機碼都必須是相同類型,而值也是如此。 但是,您可以使用不同類型的機碼和值。 例如,機碼可以是數字,而值可以是字串。 若要存取對應中的特定項目,您可以參考其機碼。

針對對應進行宣告及初始化

若要宣告對應,您必須使用 map 關鍵字。 然後,您會定義機碼和值類型,如下所示:map[T]T。 例如,若您想要建立包含學生年齡的對應,可以使用下列程式碼:

package main

import "fmt"

func main() {
    studentsAge := map[string]int{
        "john": 32,
        "bob":  31,
    }
    fmt.Println(studentsAge)
}

當您執行上述程式碼時,會看到下列輸出:

map[bob:31 john:32]

如果您不想使用項目來將對應初始化,您可以使用內建 make() 函式來在上一個區段中建立對應。 您可以使用下列程式碼來建立空白對應:

studentsAge := make(map[string]int)

對應是動態的。 您可以在建立對應之後新增、存取或移除項目。 讓我們探索那些動作。

新增項目

若要新增項目,您不需像配量那樣使用內建函式。 對應會更簡單明瞭。 您只需定義機碼和值。 如果配對不存在,則會將項目新增至對應。

讓我們使用 make 函式來重寫先前用來建立對應的程式碼。 接著,我們會將項目新增至對應。 您可以使用以下程式碼:

package main

import "fmt"

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31
    fmt.Println(studentsAge)
}

當您執行程式碼時,會得到與先前相同的輸出:

map[bob:31 john:32]

請注意,我們已將項目新增至已初始化的對應。 但是,若您嘗試使用 nil 對應進行相同的作業,就會收到錯誤訊息。 例如,下列程式碼將無法運作:

package main

import "fmt"

func main() {
    var studentsAge map[string]int
    studentsAge["john"] = 32
    studentsAge["bob"] = 31
    fmt.Println(studentsAge)
}

當您執行上述程式碼時,會發生下列錯誤:

panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
        /Users/johndoe/go/src/helloworld/main.go:7 +0x4f
exit status 2

若要避免在將項目新增至對應時遇到問題,請確定您是使用 make 函式 (如同我們在先前程式碼片段中所示) 來建立空白的對應 (而不是 nil 對應)。 只有當您新增項目時,才適用此規則。 如果您在 nil 對應中執行查閱、刪除或迴圈作業,Go 並不會發生緊急錯誤。 我們很快就會確認該行為。

存取項目

若要存取對應中的項目,您會和處理陣列或配量一樣,使用一般的下標標記法 m[key]。 以下是如何存取項目的簡單範例:

package main

import "fmt"

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31
    fmt.Println("Bob's age is", studentsAge["bob"])
}

當您在對應中使用下標標記法時,即使機碼不存在於對應上,也一律會得到回應。 當您存取不存在的項目時,Go 並不會發生緊急錯誤。 相反地,您會取得預設值。 您可以使用下列程式碼來確認該行為:

package main

import "fmt"

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31
    fmt.Println("Christy's age is", studentsAge["christy"])
}

當您執行上述程式碼時,會看到下列輸出:

Christy's age is 0

在許多情況下,當您存取不存在於對應中的項目時,Go 不會傳回錯誤的行為是合情合理的。 但有時候您會需要知道某個項目是否存在。 在 Go 中,對應的下標標記法可能會產生兩個值。 第一個是項目的值。 第二個是布林值旗標,表示機碼是否存在。

若要修正上一個程式碼片段的問題,您可以使用下列程式碼:

package main

import "fmt"

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31

    age, exist := studentsAge["christy"]
    if exist {
        fmt.Println("Christy's age is", age)
    } else {
        fmt.Println("Christy's age couldn't be found")
    }
}

當您執行上述程式碼時,會看到下列輸出:

Christy's age couldn't be found

您可以使用第二個程式碼片段來檢查對應中的機碼是否存在,然後再加以存取。

移除項目

若要從對應中移除項目,請使用內建 delete() 函式。 以下是如何從對應中移除項目的範例:

package main

import "fmt"

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31
    delete(studentsAge, "john")
    fmt.Println(studentsAge)
}

當您執行程式碼時,會取得下列輸出:

map[bob:31]

如先前所述,如果您嘗試刪除不存在的項目,Go 並不會發生緊急錯誤。 以下是該行為的範例:

package main

import "fmt"

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31
    delete(studentsAge, "christy")
    fmt.Println(studentsAge)
}

當您執行程式碼時,您不會收到錯誤,而且會看到下列輸出:

map[bob:31 john:32]

對應中的迴圈

最後,讓我們看看如何在對應中執行迴圈,以程式設計方式存取其所有項目。 若要這樣做,您可以使用範圍型迴圈,如下列範例所示:

package main

import (
    "fmt"
)

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31
    for name, age := range studentsAge {
        fmt.Printf("%s\t%d\n", name, age)
    }
}

當您執行上述程式碼時,會看到下列輸出:

john    32
bob     31

請注意,您可以將機碼和值資訊存放在不同變數中。 在此案例中,我們將機碼保留於 name 變數中,並將值保留於 age 變數中。 因此,range 會先產生項目的機碼,然後再產生該項目的值。 您可以使用 _ 變數來忽略這兩者中的任何一個,如下列範例所示:

package main

import (
    "fmt"
)

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31

    for _, age := range studentsAge {
        fmt.Printf("Ages %d\n", age)
    }
}

儘管在此案例中,以該方式列印年齡並無任何意義,但在某些情況下,您並不需要知道項目的機碼。 或者,您也可以只使用項目的機碼,如下列範例所示:

package main

import (
    "fmt"
)

func main() {
    studentsAge := make(map[string]int)
    studentsAge["john"] = 32
    studentsAge["bob"] = 31

    for name := range studentsAge {
        fmt.Printf("Names %s\n", name)
    }
}