什么是map?
map 是 Go 中的内置类型,用于存储键值对。让我们以有几个员工的创业公司为例。为简单起见,我们假设所有这些员工的名字都是唯一的。我们正在寻找一种数据结构来存储每个员工的工资。map
将非常适合此用例。员工的姓名可以是键,薪水可以是值。地图类似于 Python 等其他语言中的字典。
如何创建map?
可以通过将键和值的类型通过传递给make
函数来创建映射。以下是创建新map
的语法。
1 | make(map[type of key]type of value) |
上面的代码行创建了一个名为employeeSalary
的map
,其中包含string
键和int
值。
1 | package main |
上面的程序创建了一个命名为employeeSalary
并且键和值的类型分别为string
和int
的map。上面的程序将打印:
1 | map[] |
由于我们没有向地图添加任何元素,因此它是空的。
将项目添加到地图
将新项目添加到地图的语法与数组相同。下面的程序将一些新员工添加到employeeSalary
地图中。
1 | package main |
我们增加了三名员工steve
,jamie
以及mike
他们相应的工资。
上面的程序打印:
1 | employeeSalary map contents: map[steve:12000 jamie:15000 mike:9000] |
也可以在声明本身期间初始化映射。
1 | package main |
上面的程序employeeSalary
在声明过程中声明并添加了两个元素。后来又添加了一个带键的元素mike
。程序打印
1 | employeeSalary map contents: map[jamie:15000 mike:9000 steve:12000] |
不必只有字符串类型才是键。所有可比较的类型,例如 boolean、integer、float、complex、string,… 也可以是键。即使是用户定义的类型(例如struct)也可以是键。如果您想了解更多关于可比较类型的信息,请访问http://golang.org/ref/spec#Comparison_operators
地图的零值
地图的零值是nil
。如果您尝试向地图添加元素,则会发生nil
运行时panic。因此,必须在添加元素之前初始化地图。
1 | package main |
在上面的程序employeeSalary
中,nil
我们正在尝试向地图添加一个新键。程序将因错误而panic
1 | panic: assignment to entry in nil map |
从映射中检索键的值
现在我们已经向地图添加了一些元素,让我们学习如何检索它们。map[key]
是检索地图元素的语法。
1 | package main |
上面的程序非常简单。jamie
检索并打印员工的工资。程序打印
1 | Salary of jamie is 15000 |
如果一个元素不存在会发生什么?该映射将返回该元素类型的零值。在employeeSalary
map 的案例下,如果我们尝试访问不存在的元素,将返回int
的零值0
。
1 | package main |
上述程序的输出是:
1 | Salary of joe is 0 |
上述程序将返回 joe 的薪水为0
。当我们尝试检索地图中不存在的键的值时,不会出现运行时错误。
检查密钥是否存在
在上一节中我们了解到,当键不存在时,将返回类型的零值。当我们想要找出键是否真的存在于地图中时,这无济于事。
例如,我们想知道employeeSalary
地图中是否存在某个键。
1 | value, ok := map[key] |
以上是找出特定键是否存在于映射中的语法。如果ok
为真,则该键存在且其值存在于变量value
中,否则该键不存在。
1 | package main |
在上面的程序中,在第 1 行。13、ok
将是假的,因为joe
不存在。因此程序将打印,
1 | joe not found |
遍历地图中的所有元素
for
循环的range
形式用于迭代地图的所有元素。
1 | package main |
上述程序输出,
1 | Contents of the map |
一个重要的事实是,在使用时从映射中检索值的顺序for range
不能保证对于程序的每次执行都是相同的。它也与将元素添加到地图的顺序不同
从地图中删除项目
delete(map, key)key
是从 a中删除的语法map
。删除函数不返回任何值。
1 | package main |
上面的程序删除密钥steve
并打印
1 | map before deletion map[steve:12000 jamie:15000 mike:9000] |
如果我们尝试删除地图中不存在的键,则不会出现运行时错误。
Map of structs
到目前为止,我们只在地图中存储了员工的工资。如果我们也能够在地图中存储每个员工的国家,那不是很好吗?这可以通过使用structs
的映射来实现。员工可以表示为包含字段salary 和country 的结构,它们将与字符串键和结构值一起存储在地图中。让我们编写一个程序来了解如何做到这一点。
1 | package main |
在上面的程序中,employee
struct 包含字段salary
和country
。我们创建了三个员工emp1
,emp2
并且emp3
。
在第25行,我们用我们创建的三个员工初始化一个键类型string
和值类型为employee
的映射。
map在第 31 行迭代,员工详细信息打印在下一行。该程序将打印:
1 | Employee: Mike Salary:$13000 Country: India |
地图长度
地图的长度可以使用len函数确定。
1 | package main |
*上面程序中的len(employeeSalary)
*返回地图的长度。上面的程序打印,
1 | length is 2 |
地图是引用类型
与slices类似,maps 是引用类型。当映射分配给新变量时,它们都指向相同的内部数据结构。因此,在一个中所做的更改将反映在另一个中。
1 | package main |
在上述程序中的第 14 行,employeeSalary
分配给modified
。 在下一行中,mike
的salary
在 map 中更改为18000。mike的salary现在在employeeSalary
中也为18000。程序输出:
1 | Original employee salary map[jamie:15000 mike:9000 steve:12000] |
当映射作为参数传递给函数时,情况也是如此。当函数内的地图发生任何变化时,调用者也可以看到它。
Maps equality
无法使用==
运算符比较地图。==
只能用于检查地图是否为nil
。
1 | package main |
上述程序将无法编译并出现错误
1 | invalid operation: map1 == map2 (map can only be compared to nil) |
检查两个映射是否相等的一种方法是逐个比较每个映射的各个元素。另一种方法是使用反射。我鼓励你为此编写一个程序并让它工作:)。