文章目录
导言
- 原文链接: Part 13: Maps
- If translation is not allowed, please leave me in the comment area and I will delete it as soon as possible.
map
map
是什么?
map
是 Go
语言 中内置的一种类型,它将键值相关联,我们可以通过 键key
来获取对应的 值value
。
map
的中文是:映射。
怎么创建 map
?
将 key
与 value
的类型传递给 make
函数,我们就能创建一个 map
。
make(map[type of key]type of value)
这就是创建 map
的句式。
personSalary := make(map[string]int)
上面的代码创建了一个名为 personSalary
的 map
,这个 map
拥有 string
类型的 key
、int
类型的value
。
map
的零值是 nil
,为它添加键值对,将会引发异常。因此, 必须使用 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)
}
}
在上面程序中,因为 personSalary
为 nil
,所以它将会被 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)
}
上面的程序将会输出:
personSalary map contents: map[steve:12000 jamie:15000 mike:9000]
在 map
声明时,我们也可以初始化 map
。
package main
import (
"fmt"
)
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("personSalary map contents:", personSalary)
}
在上面的代码中,在声明期间,我们初始化了 personSalary
并为它添加了 2
个键值对。之后,我们还为它添加了一个键 mike
。
运行这个程序,输出如下:
personSalary map contents: map[steve:12000 jamie:15000 mike:9000]
键的类型不一定非得是 string
。所有 可比较的类型,如 boolean
、integer
、float
、complex
、string
… 都能作为键、值的类型。如果你想深入了解 可比较类型,你可以访问 这个链接。
访问 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])
}
上面的程序十分直接。雇员jamie
的 工资salary
被检索,并被打印出来。程序的输出是:
Salary of jamie is 15000.
如果元素不存在呢?此时,map
会返回对应元素类型的零值。对本例子的 personSalary
来说,如果我们试着去访问一个元素 — 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"])
}
程序的输出是:
Salary of jamie is 15000
Salary of joe is 0
上面的程序将 joe
的 工资 salary
视作 0
,并进行返回。当 personSalary
中没有 键joe
时,访问 键joe
并不会引发运行时错误。
假如现在,我们想要知道 map
中是否存在某个 key
呢?
value, ok := map[key]
上面的句式可以告诉你,某个特定的 键key
是否存在于 map
中。如果 ok
为 true
,此时表示 键key
存在,而且对应的值将会被存放在 变量value
中。而当 ok
为 false
时,这表示 键key
不存在。
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")
}
}
在上面程序的第 15
行,ok
将会等于 false
,因为 joe
不存在。程序输出如下:
joe not found
for
循环的 range
形式可以用于遍历 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)
}
}
上面程序的输出如下:
All items of a map
personSalary[mike] = 9000
personSalary[steve] = 12000
personSalary[jamie] = 15000
使用 for range
遍历 map
,并不能保证元素输出的次序是固定的。即有可能出现:第一次遍历时,输出的是 a、b
,第二次遍历时,输出可能是 b、a
。
删除键值对
delete(map, key)
能删除 map
中的键值对,而且这个函数没有返回值。
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)
}
上面的代码删除了 键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))
}
上面程序的 len(personSalary)
可以得到 personSalary
的元素个数。程序最终会输出:
length is 3
map
是引用类型
与切片类型相同,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)
}
上面程序的第 14
行,personSalary
被赋值给 newPersonSalary
。在接下来的一行,我们通过 newPersonSalary
, 将 mike
的工资改为了 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 {
}
}
上面的程序将会抛出编译错误:
invalid operation: map1 == map2 (map can only be compared to nil).
要判断两个 map
是否相同,我们只能一对一的比较它们内部的元素。我鼓励你去尝试一下~
原作者留言
我已经把上面的概念整合到了一个程序,你可以在 github 下载。
优质内容来之不易,您可以通过该 链接 为我捐赠。
最后
感谢原作者的优质内容。
这是我的第五次翻译,欢迎指出文中的任何错误。