ArcherWong博客
首页
博客
golang笔记---关联数组(map)
作者:ArcherWong
分类:golang
时间:2019-01-03 21:34:24
阅读:1342
[TOC] map 是一种特殊的数据结构:一种元素对(pair)的无序集合,pair 的一个元素是 key,对应的另一个元素是 value,所以这个结构也称为关联数组或字典。这是一种快速寻找值的理想结构:给定 key,对应的 value 可以迅速定位。 map 这种数据结构在其他编程语言中也称为字典(Python)、hash 和 HashTable 等。 # 声明、初始化和make ## 概念 map 是引用类型,可以使用如下声明: ``` var map1 map[keytype]valuetype var map1 map[string]int ``` (`[keytype]` 和 `valuetype` 之间允许有空格,但是 gofmt 移除了空格) 在声明的时候不需要知道 map 的长度,**map 是可以动态增长的**。未初始化的 map 的值是 nil。 **key 可以是任意可以用 == 或者 != 操作符比较的类型,比如 string、int、float;value 可以是任意类型的**。 map 传递给函数的代价很小:在 32 位机器上占 4 个字节,64 位机器上占 8 个字节,无论实际上存储了多少数据。通过 key 在 map 中寻找值是很快的,比线性查找快得多,但是仍然比从数组和切片的索引中直接读取要慢 100 倍;所以如果你很在乎性能的话还是建议用切片来解决问题。 map 也可以用函数作为自己的值,这样就可以用来做分支结构:key 用来选择要执行的函数。 如果 key1 是 map1 的key,那么 map1[key1] 就是对应 key1 的值,就如同数组索引符号一样(数组可以视为一种简单形式的 map,key 是从 0 开始的整数)。 key1 对应的值可以通过赋值符号来设置为 val1:`map1[key1] = val1`。 令 `v := map1[key1]` 可以将 key1 对应的值赋值给 v;如果 map 中没有 key1 存在,那么 v 将被赋值为 map1 的值类型的空值。 初始化方法: ``` mapCreated := make(map[string]float32) ``` 相当于: ``` mapCreated := map[string]float32{} ``` **不要使用 new,永远用 make 来构造 map** ## map 容量 和数组不同,map 可以根据新增的 key-value 对动态的伸缩,因此它不存在固定长度或者最大限制。但是你也可以选择标明 map 的初始容量 capacity,就像这样:make(map[keytype]valuetype, cap)。例如: ``` map2 := make(map[string]float32, 100) ``` 当 map 增长到容量上限的时候,如果再增加新的 key-value 对,map 的大小会自动加 1。所以**出于性能的考虑,对于大的 map 或者会快速扩张的 map,即使只是大概知道容量,也最好先标明**。 ## 用切片作为 map 的值 既然一个 key 只能对应一个 value,而 value 又是一个原始类型,那么如果一个 key 要对应多个值怎么办?例如,当我们要处理unix机器上的所有进程,以父进程(pid 为整形)作为 key,所有的子进程(以所有子进程的 pid 组成的切片)作为 value。通过将 value 定义为 []int 类型或者其他类型的切片,就可以优雅的解决这个问题。 这里有一些定义这种 map 的例子: ``` mp1 := make(map[int][]int) mp2 := make(map[int]*[]int) ``` # 测试键值对是否存在及删除元素 测试键值对是否存在: ``` val1, isPresent = map1[key1] ``` isPresent 返回一个 bool 值:如果 key1 存在于 map1,val1 就是 key1 对应的 value 值,并且 isPresent为true;如果 key1 不存在,val1 就是一个空值,并且 isPresent 会返回 false。 如果你只是想判断某个 key 是否存在而不关心它对应的值到底是多少,你可以这么做: ``` _, ok := map1[key1] // 如果key1存在则ok == true,否则ok为false ``` 或者和 if 混合使用: ``` if _, ok := map1[key1]; ok { // ... } ``` 从map1中删除key1: ``` delete(map1, key1) ``` # map类型的切片 假设我们想获取一个 map 类型的切片,我们必须使用两次 make() 函数,第一次分配切片,第二次分配 切片中每个 map 元素。 ``` package main import "fmt" func main() { // Version A: items := make([]map[int]int, 5) for i:= range items { items[i] = make(map[int]int, 1) items[i][1] = 2 } fmt.Printf("Version A: Value of items: %v\n", items) // Version B: NOT GOOD! items2 := make([]map[int]int, 5) for _, item := range items2 { item = make(map[int]int, 1) // item is only a copy of the slice element. item[1] = 2 // This 'item' will be lost on the next iteration. } fmt.Printf("Version B: Value of items: %v\n", items2) } ``` 输出结果: ``` Version A: Value of items: [map[1:2] map[1:2] map[1:2] map[1:2] map[1:2]] Version B: Value of items: [map[] map[] map[] map[] map[]] ``` 需要注意的是,应当像 A 版本那样通过索引使用切片的 map 元素。**在 B 版本中获得的项只是 map 值的一个拷贝而已,所以真正的 map 元素没有得到初始化**。 # map 的排序 map 默认是无序的,不管是按照 key 还是按照 value 默认都不排序。 如果你想为 map 排序,需要将 key(或者 value)拷贝到一个切片,再对切片排序(使用 sort 包),然后可以使用切片的 for-range 方法打印出所有的 key 和 value。 下面有一个示例: 示例 ort_map.go: ``` // the telephone alphabet: package main import ( "fmt" "sort" ) var ( barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23, "delta": 87, "echo": 56, "foxtrot": 12, "golf": 34, "hotel": 16, "indio": 87, "juliet": 65, "kili": 43, "lima": 98} ) func main() { fmt.Println("unsorted:") for k, v := range barVal { fmt.Printf("Key: %v, Value: %v / ", k, v) } keys := make([]string, len(barVal)) i := 0 for k, _ := range barVal { keys[i] = k i++ } sort.Strings(keys) fmt.Println() fmt.Println("sorted:") for _, k := range keys { fmt.Printf("Key: %v, Value: %v / ", k, barVal[k]) } } ``` 输出结果: ``` unsorted: Key: bravo, Value: 56 / Key: echo, Value: 56 / Key: indio, Value: 87 / Key: juliet, Value: 65 / Key: alpha, Value: 34 / Key: charlie, Value: 23 / Key: delta, Value: 87 / Key: foxtrot, Value: 12 / Key: golf, Value: 34 / Key: hotel, Value: 16 / Key: kili, Value: 43 / Key: lima, Value: 98 / sorted: Key: alpha, Value: 34 / Key: bravo, Value: 56 / Key: charlie, Value: 23 / Key: delta, Value: 87 / Key: echo, Value: 56 / Key: foxtrot, Value: 12 / Key: golf, Value: 34 / Key: hotel, Value: 16 / Key: indio, Value: 87 / Key: juliet, Value: 65 / Key: kili, Value: 43 / Key: lima, Value: 98 / ``` **参考资料** https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/directory.md
标签:
上一篇:
golang笔记---template模板语法
下一篇:
guacamole实现剪切复制
文章分类
css
elasticsearch
git
golang
guacamole
javascript
letsencrypt
linux
nginx
other
php
python
vue
web
阅读排行
centos7.3配置guacamole
golang笔记---关联数组(map)
letsencrypt证书-管理工具certbot
golang笔记---template模板语法
nginx笔记-proxy_cache缓存详解
友情链接
node文件
laravel-vue
ArcherWong的博客园