映射(map)
映射是一种数据结构,用于存储一系列无序的键值对,映射基于键来存值,能够快速检索数据。键就像索引一样,指向与该键关联的值。
映射的实现
Go语言中 map 的底层是哈希(hash)表实现的,它的源码在 $GOROOT/src/pkg/runtime/hashmap.go/
可以查看它的实现细节。Go语言的 map 是一个数组列表,不是像 C++ 一样使用红黑树,与传统的 hashmap 一样,Go语言的 map 由一个个 bucket 组成。在这个数组列表中的每一个元素都被称为 bucket 的结构体,每个 bucket 可以保存为 8 个键值对,所有元素将被 hash 算法填入到数组的 bucket 中;当 bucket 填满后,会使用一个 overflow 指针来扩展一个 bucket ,从而形成链表,以此解决 hash 冲突的问题。
映射的创建和初始化
- 使用make函数创建映射
- 使用映射字面量(常用)
func main(){
//使用make函数创建映射
a1 := make(map[string]int)
fmt.Println(a1) //打印零值
//使用映射字面量初始化
a1 = map[string]int{"Cat":1,"Dog":2,"Bee":3}
fmt.Println(a1)
}
/*
map[]
map[Bee:3 Cat:1 Dog:2]
*/
使用映射字面量初始化是常用的方法,映射的初始长度会根据初始化时指定的键值对的数量来确定。映射的键可以是任何类型的值,内置类型或者结构类型都可以,不过需要确定这个值可以用 == 比较运算符做比较。需要注意的是,切片、函数以及包含切片结构类型由于具有引用语义,所以这些数据类型都不能用作映射的键,编译器会报错:
//创建一个映射,使用字符串切片作为映射的键
func main(){
dict := map[[]string]int{}
fmt.Println(dict)
}
/*
command-line-arguments
invalid map key type []string
*/
但是可以使用切片作为映射的值
//创建一个映射,使用字符串切片作为映射的值
func main(){
dict := map[int][]string{}
fmt.Println(dict)
}
/*
map[]
*/
映射的使用
-
元素赋值
通过指定适当类型的键并给这个键赋值就完成了映射的键值对赋值。
func main(){ //使用空字面量创建初始化后的空映射 dict := map[string]int{} fmt.Println(dict) //映射赋值 dict["Star"] = 1 fmt.Println(dict) //使用make函数创建初始化后的空映射 dict1 := make(map[string]int) fmt.Println(dict1) //映射赋值 dict1["Moon"] = 2 fmt.Println(dict1) } /* map[] map[Star:1] map[] map[Moon:2] */
声明一个未初始化的映射可以产生值为 nil 的映射。nil 映射不能用于存储键值对,否则编译器会抛出panic异常。
func main(){ //创建一个未初始化的空映射,值为 nil var dict map[string]int //nil 映射赋值 dict["Star"] = 1 fmt.Println(dict) } /* panic: assignment to entry in nil map */
映射的查找和遍历
映射取值有两种方式:
- 先获取对应键的值,再判断是否存在,若存在则打印值,若不存在则什么也不做
- 先取取对应键的值,再判断值是否为零值 (如果非空,说明存在;如果为空,说明不存在)
func main() { //使用字面量创建初始化后的映射 dict := map[string]int{"Cat": 1, "Dog": 2, "Bee": 3} //方法一:映射取值,获得键对应的值 value, exists := dict["Dog"] if exists { fmt.Println(value) } //方法二:先取对应键的值,再判断值是否为零值 如果非空,说明存在;如果为空,说明不存在 value = dict["Cat"] if value != 0 { fmt.Println(value) } } /* 2 1 */
在Go语言里,通过键来索引映射时,即便这个键不存在,也会返回该值对应类型的零值。
-
映射遍历
func main() { //使用字面量创建初始化后的映射 dict := map[string]int{"Cat": 1, "Dog": 2, "Bee": 3} //映射遍历 for i,v := range dict { fmt.Println(i,v) } } /* Cat 1 Dog 2 Bee 3 */
-
元素删除
Go语言里提供了内置函数 delete() 用于删除容器内的元素。
func main() { //使用字面量创建初始化后的映射 dict := map[string]int{"Cat": 1, "Dog": 2, "Bee": 3} fmt.Println(dict) //删除元素 delete(dict,"Cat") fmt.Println(dict) } /* map[Bee:3 Cat:1 Dog:2] map[Bee:3 Dog:2] */
将映射传递给函数
在函数间传递映射并不会制造出该映射的一个副本
func main() {
// 创建一个映射,存储颜色以及颜色对应的十六进制代码
myColors := map[string]string{
"AliceBlue":"#f0f8ff",
"Coral":"#ff7F50",
"DarkGray":"#a9a9a9",
"ForestGreen": "#228b22",
}
// 显示映射里的所有颜色
for key, value := range myColors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
fmt.Println()
// 调用函数来移除指定的键
removeColor(myColors, "Coral")
// 显示映射里的所有颜色
for key, value := range myColors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
}
// removeColor 将指定映射里的键删除
func removeColor(colors map[string]string, key string) {
delete(colors, key)
}
/*
Key: AliceBlue Value: #f0f8ff
Key: Coral Value: #ff7F50
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
Key: AliceBlue Value: #f0f8ff
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
*/
有疑问加站长微信联系(非本文作者)