[譯] part 13: golang 對映 map

咔嘰咔嘰發表於2019-04-14

什麼是 map

map 是 Go 中的內建型別,它將值與鍵相關聯。可以使用相應的鍵查詢該值。

怎麼建立 map

可以指定鍵和值的型別,然後通過make函式來建立一個 map,語法為make(map[type of key]type of value)

personSalary := make(map[string]int) 
複製程式碼

上面的程式碼建立了一個叫personSalary的 map,它的鍵的型別為string,值的型別為int

map 的零值為nil,如果你嘗試給空 map 增加元素,執行時將會觸發 panic,因此,必須使用make函式初始化 map。

package main

import (  
    "fmt"
)

func main() {  
    var personSalary map[string]int
    if personSalary == nil {
        fmt.Println("map is nil. Going to make one.")
        personSalary = make(map[string]int)
    }
}
複製程式碼

Run in playground

在上述程式碼中,personSalary是空的,所以必須用 make 函式初始化。該程式碼輸出map is nil. Going to make one.

給 map 增加元素

給 map 增加元素的語法和陣列一樣,下面的程式碼將給personSalary增加新的元素。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := make(map[string]int)
    personSalary["steve"] = 12000
    personSalary["jamie"] = 15000
    personSalary["mike"] = 9000
    fmt.Println("personSalary map contents:", personSalary)
}
複製程式碼

Run in playground

上面的程式將會輸出,personSalary map contents: map[steve:12000 jamie:15000 mike:9000]

map 也可以在初始化的時候新增元素,

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int {
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    fmt.Println("personSalary map contents:", personSalary)
}
複製程式碼

Run in playground

上面的程式宣告瞭personSalary,並在宣告過程中為它新增了兩個元素。之後又新增了一個鍵為mike的元素。該程式輸出

personSalary map contents: map[steve:12000 jamie:15000 mike:9000]  
複製程式碼

鍵的型別並不僅僅是string。所有可比較的型別,如booleanintegerfloatcomplexstring,...也可以是鍵。如果你想了解有關類似型別的更多資訊,請訪問http://golang.org/ref/spec#Comparison_operators

訪問 map 的元素

現在我們已經向 map 新增了一些元素,讓我們學習如何訪問它們。 map[key]是訪問 map 元素的語法。

 
package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    employee := "jamie"
    fmt.Println("Salary of", employee, "is", personSalary[employee])
}
複製程式碼

Run in playground

上述程式非常簡單。員工 Jamie 的工資被找到並列印出來。程式輸出Salary of jamie is 15000.

如果元素不存在會發生什麼?map 將返回該元素型別的零值。在personSalary的例子中,如果我們嘗試訪問當前不存在的元素,則返回int的零值 0。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    employee := "jamie"
    fmt.Println("Salary of", employee, "is", personSalary[employee])
    fmt.Println("Salary of joe is", personSalary["joe"])
}
複製程式碼

Run in playground

上面的程式將輸出,

Salary of jamie is 15000  
Salary of joe is 0  
複製程式碼

上面的程式返回了 joe 的工資為 0,我們並沒有得到 joe 不存在於personSalary中的資訊。

如果我們想知道 map 中是否存在某個鍵,該怎麼辦?

value, ok := map[key] 
複製程式碼

上面的語法就是找出 map 中是否存在某個鍵,如果oktrue的話,那就說明鍵存在,並且值為value。否則okfalsevalue為空。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    newEmp := "joe"
    value, ok := personSalary[newEmp]
    if ok == true {
        fmt.Println("Salary of", newEmp, "is", value)
    } else {
        fmt.Println(newEmp,"not found")
    }

}
複製程式碼

Run in playground

上述程式的第 15 行,由於 joe 不存在,okfalse。因此程式輸出

joe not found
複製程式碼

使用range for可以迭代所有的 map 元素。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    fmt.Println("All items of a map")
    for key, value := range personSalary {
        fmt.Printf("personSalary[%s] = %d\n", key, value)
    }

}
複製程式碼

Run in playground

上述程式輸出,

All items of a map  
personSalary[mike] = 9000  
personSalary[steve] = 12000  
personSalary[jamie] = 15000  
複製程式碼

一個重要的事實是,使用range for迭代獲取元素的順序,並不能保證結果每次相同。

刪除元素

從 map 中刪除一個 key 的語法為delete(map, key),刪除函式不返回任何值。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    fmt.Println("map before deletion", personSalary)
    delete(personSalary, "steve")
    fmt.Println("map after deletion", personSalary)

}
複製程式碼

Run in playground

上述程式刪除 key 為 steve 的元素,程式輸出

map before deletion map[steve:12000 jamie:15000 mike:9000]  
map after deletion map[mike:9000 jamie:15000]  
複製程式碼

map 的長度

可以使用len函式確定 map 的長度。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    fmt.Println("length is", len(personSalary))

}
複製程式碼

Run in playground

上述程式使用len(personSalary)計算 map 的長度,輸出,length is 3

map 是指標傳遞

和 slice 一樣,map 也是指標傳遞的。將 map 賦值給新變數時,它們都指向相同的內部資料結構。因此修改一個會影響另外一個。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    fmt.Println("Original person salary", personSalary)
    newPersonSalary := personSalary
    newPersonSalary["mike"] = 18000
    fmt.Println("Person salary changed", personSalary)

}
複製程式碼

Run in playground

在上述程式碼的第 14 行,personSalary賦值給newPersonSalary。在下一行,mike 的工資被修改為 18000,personSalary中的薪水也會變成 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

package main

func main() {  
    map1 := map[string]int{
        "one": 1,
        "two": 2,
    }

    map2 := map1

    if map1 == map2 {
    }
}
複製程式碼

Run in playground

上述的程式碼將會丟擲編譯錯誤,invalid operation: map1 == map2 (map can only be compared to nil).

檢查兩個 map 是否相等的方法是逐個比較每個元素是否一樣。為此編寫一個一個函式是一個不錯的方法:)

相關文章