Golang中存储键值对的数据类型是映射,即map,由于映射这个中文词汇比较生硬,又没有其他更好的中文词,因此后面还是直接用英文map。
什么是map
Golang中map是一种用来存储键值对的数据类型,可以通过键(key) 来设置 或读取 对应的值(value) 。
创建map
可以使用make
函数来创建一个map,语法如下:
Copy make(map[key_type]value_type)
例如我们可以创建一个名为personSalary
的map来存储大家的薪水:
Copy personSalary := make(map[string]int)
该map的key类型为string
,value类型为int
。
map数据类型对应的零值 为nil
。如果尝试向值为nil
的map中添加元素会报错。因此一般情况下需要通过make
函数来初始化一个空map。
Copy 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)
}
}
Go Playground在线运行 这里map personSalary
值为nil,因此我们使用make
函数创建了一个map并赋值给了personSalary
。执行结果如下:
Copy map is nil. Going to make one.
添加元素
向map内添加元素的语法跟数组添加元素一致。下面的程序向map personSalary
内添加了几项元素:
Copy 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)
}
Go Playground在线运行 该程序执行结果如下:
Copy personSalary map contents: map[jamie:15000 mike:9000 steve:12000]
map也可以在声明时同时进行初始化。
Copy package main
import "fmt"
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("personSalary map contents:", personSalary)
}
Go Playground在线运行 这里声明了map personSalary
,并同时初始化了两项元素。然后接着又添加了一个key为mike
的元素。
Golang中不仅仅是字符串可以做为key,所有可比较 类型比如布尔、整型、浮点型、复数型等等都可以作为map的key,更多关于可比较 类型内容可以参考https://golang.org/ref/spec#Comparison_operators
访问元素
我们已经了解如何向map中添加元素了,现在我们看下如何访问map元素。访问map元素的语法为map[key]
。
Copy 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])
}
Go Playground在线运行 该程序非常简单,我们取出了jamie
(key)的工资(value)并打印出来。结果如下:
Copy Salary of jamie is 15000
如果我们访问的某个key在map中不存在,map会返回value类型对应的零值。比如对于personSalary
,如果我们访问的元素不存在,则会返回int
类型对应的零值0
。
Copy package main
import "fmt"
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
fmt.Println("Salary of joe is", personSalary["joe"])
}
Go Playground在线运行 该程序执行结果如下:
虽然mappersonSalary
中并没有元素joe
,但是该程序执行并没有报错,personSalary["joe"]
返回了值0
。
那如果我们就是想知道map中是否含有某个key
怎么办呢?Golang提供了如下方式:
Copy value, ok := map[key]
如果ok
为true
,表示map中含有该key
,否则不含有。
Copy package main
import "fmt"
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
newEmp := "joe"
salary, ok := personSalary[newEmp]
if ok == true {
fmt.Println("Salary of", newEmp, "is", salary)
} else {
fmt.Println(newEmp, "not found")
}
}
Go Playground在线运行 这里,由于key joe
不存在,因此ok
值为false。输出为:
类似数组和切片,我们可以使用for range
来迭代访问map。
Copy package main
import "fmt"
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
for key, value := range personSalary {
fmt.Printf("personSalary[%s] = %d\n", key, value)
}
}
Go Playground在线运行 输出如下:
Copy personSalary[steve] = 12000
personSalary[jamie] = 15000
使用for range
迭代访问map有一点需要注意,每次迭代访问map元素的访问次序不保证 。
删除元素
从map中删除元素的语法为delete(map, key)
。这里delete
函数调用时无返回值。
Copy package main
import "fmt"
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
fmt.Println("map before deletion", personSalary)
delete(personSalary, "steve")
fmt.Println("map after deletion", personSalary)
}
Go Playground在线运行 这里删除了key
为steve
的元素,输出如下:
Copy map before deletion map[jamie:15000 steve:12000]
map after deletion map[jamie:15000]
获取map中元素个数
len
函数可以获取map中元素的个数。
Copy package main
import "fmt"
func main() {
personSalary := map[string]int {
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("length is", len(personSalary))
}
Go Playground在线运行 该程序输出为length is 3
。
map是引用类型
Golang中,map和切片(slice)相同,都是引用类型。如果我们把一个map变量赋值给另外一个变量,这两个变量指向同一个底层存储空间,任何一个变量对内部元素进行了修改都会反映到另一个变量上。
Copy 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)
}
Go Playground在线运行 这里我们将personSalary
赋值给了一个新变量newPersonSalary
,然后通过该新变量修改了mike
的值,由于这两个map指向的底层数据存储空间是一个,因此输出如下:
Copy Original person salary map[jamie:15000 mike:9000 steve:12000]
Person salary changed map[jamie:15000 mike:18000 steve:12000]
这点在函数传参的时候也会同样试用,需要注意。
判断相等
两个map不能通过==
运算符进行比较,==
仅可以用来跟nil
值进行比较。
Copy package main
func mian() {
map1 := map[string]int {
"one": 1,
"two": 2,
}
map2 := map1
if map1 == map2 {
}
}
Go Playground在线运行 该程序执行会报如下错误:
Copy invalid operation: map1 == map2 (map can only be compared to nil)
如果我们确实像判断两个map是否相等,可以遍历两个map来判断每个键值对是否相同,以间接判断。