You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
4.3 KiB
95 lines
4.3 KiB
2 years ago
|
# 第四章 VimL 数据结构进阶
|
||
|
|
||
|
## 4.2 通用的字典结构
|
||
|
|
||
|
为什么说字典是通用结构。因为在 VimL 中字典是最复杂的内置类型了,而更复杂的数据
|
||
|
结构都能以字典为基础构建出来。不过从基础的概念上理解,字典与列表其实也有些相似
|
||
|
之处,当掌握了列表之后,对字典的用法也就容易了。
|
||
|
|
||
|
### 字典与列表的异同
|
||
|
|
||
|
在其他一些(脚本)语言中,对应 VimL 的列表与字典的概念,也叫数组与关联数组。所
|
||
|
以字典也可以看成是一种特殊的列表,无序的以字符串为索引的列表。字典的索引也叫键
|
||
|
,在 VimL 中,字典的键只能是字符串,当数字用作字典键时也被隐式转为字符串。其它
|
||
|
类型的值,一般不能用作字典的键。
|
||
|
|
||
|
请看这个示例:
|
||
|
```vim
|
||
|
: let list = range(10)
|
||
|
: let dict = {}
|
||
|
: for i in range(10)
|
||
|
: let dict[i] = i
|
||
|
: endfor
|
||
|
|
||
|
: echo 'list =' list
|
||
|
: echo 'dict =' dict
|
||
|
|
||
|
: for [k, v] in items(dict)
|
||
|
: echo k v
|
||
|
: endfor
|
||
|
```
|
||
|
用 range() 创建了一个列表 list,包含的元素是 0-9 这十个数字。然后创建了一个空
|
||
|
字典 dict,再用循环为字典增加键值,也用相同的 0-9 这十个数字作为键与值。这样,
|
||
|
在表观上,dict 与 list 似乎保存着相同的元素,用相同的索引能得到相同的值,比如
|
||
|
`dict[5]` 与 `list[5]` 都得到数值 `5`。但通过 `:echo dict` 可以发现,dict 字典
|
||
|
的键,其实不是数字,而是字符串(`'0', '1'`等)。
|
||
|
|
||
|
为理解遍历字典的范式 `for [k, v] in items(dict)`,可先用 `echo items(dict)` 查
|
||
|
看这是什么。可见 `items(dict)` 返回一个列表,该列表的每个元素又是个小列表,包
|
||
|
含键与值两个元素。所以你明白了,字典的元素,不像列表的元素那么简单的一个值,而
|
||
|
是一个“键值”对。所谓关联数组名称也源于此,每个键对应一个值。键是唯一的,但值可
|
||
|
不唯一,即不同键可关联相同的值。
|
||
|
|
||
|
在字典循环中,也用到了上节介绍的列表解包的多重赋值的功能,相当于如下语句:
|
||
|
```vim
|
||
|
: let [k, v] = items(dict)[0]
|
||
|
: let [k, v] = items(dict)[1]
|
||
|
: ...
|
||
|
: let [k, v] = items(dict)[9]
|
||
|
```
|
||
|
也因此,`[k, v]` 必须用中括号括起来。
|
||
|
|
||
|
在这个特殊的例子中,遍历字典所得的值也许是与列表一样有序。但请记住,字典不保证
|
||
|
有序。同时,在一般应用中,最好不要用连续的数字作为字典的键,那应该直接使用列表
|
||
|
更高效且方便。但如果是很稀疏的有大量空洞的列表,则用字典或许是有意义的。如:
|
||
|
```vim
|
||
|
: let dict[10] = 'a'
|
||
|
: let dict[100] = 'b'
|
||
|
: let dict[1000] = 'c'
|
||
|
```
|
||
|
这样,只为 dict 增加了三个元素。但若为 `list[1000]='c'` 赋值,则会为列表增加
|
||
|
1000 个元素,中间的无用索引都浪费了。
|
||
|
|
||
|
在常用使用字典时,建议用简单字符串索引,所谓简单字符串,即是可充当 VimL 标记符
|
||
|
(变量名)的字符串。这时,字典的中括号索引可用点索引简化写法,即 `dict['name']`
|
||
|
可简化等效于 `dict.name`。当索引是一个字符串变量时,用中括号索引更方便,即
|
||
|
`dict[varname]`。
|
||
|
|
||
|
还有一点需要重点理解的是,字典变量与列表变量一样,是引用而已。请看以下示例:
|
||
|
```vim
|
||
|
: let d1 = {}
|
||
|
: let d2 = {}
|
||
|
: echo d1 == d2
|
||
|
: echo d1 is d2
|
||
|
: let d3 = d1
|
||
|
: echo d3 is d1
|
||
|
```
|
||
|
虽然 `d1` 与 `d2` 都是空字典,它们按值比较是一样的,但其实是不同的字典实体,用
|
||
|
`is` 比较显示不一样。为另一个变量 `d3` 赋值后,就指向相同的字典实体了。
|
||
|
|
||
|
### 操作字典的内置函数
|
||
|
|
||
|
上节介绍的许多关于列表的函数,也可作用于字典。只是其他参数意义可能不一样,对于
|
||
|
字典时,一般是根据键来处理的。详情请查阅 `:h dict-functions`。
|
||
|
|
||
|
但以下几个函数是字典特有的:
|
||
|
|
||
|
* has\_key(dict, key) 检查一个字典是否含有某个键。
|
||
|
* keys(dict) 返回由字典的所有键组成的列表。
|
||
|
* values(dict) 返回由字典的所有值组成的列表。
|
||
|
* items(dict) 返回由字典的所有键值对组成的列表。
|
||
|
|
||
|
这几个返回列表的函数一般用于 `for ... in` 循环中。字典的内部存储是无序的,但可
|
||
|
用 `for ... in sort(keys(dict))` 根据键顺序遍字典。
|
||
|
|