zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Vim技能修炼教程(13) - 变量

Vim教程变量 技能 13 修炼
2023-09-11 14:19:42 时间
VimScript变量

上节我们介绍了Python和Ruby来编写Vim插件的方式。
不过,Python和Ruby并不是所有的Vim都支持的功能,如果以最小依赖的原则来说,还是原汁原味的Vimscripts是放置四海Vim而皆灵的方式。当代码规模变大时,Python,Ruby,Perl这些语言的引入将带来较高的效率。但是Vimscripts仍然是最基本的Vim语言,值得我们首先学好。

做为一种脚本语言,Vimscript当然是支持变量的。
不过Vimscript的特色是,显式指定作用域。也就是说,一个变量,需要在名字前加作用域前缀。

这些作用域前缀有:

b: 缓冲区级作用域 w: 窗口级作用域 t: 标签页级作用域 g: 全局变量 l: 函数内局部变量 s: vim脚本文件级作用域 a: 函数参数 v: Vim专用的全局变量

如果未指定前缀,定义于函数内部的默认为l:,而定义于函数之外的默认为g:.

Vimscript通过:let命令来为变量赋值,赋值之前不需要定义。

访问属性和寄存器

Vimscript通过 属性名的方式来访问属性,也就是除了:set之外,我们也可以通过:let为变量赋值。

同变量一样,属性也有作用域,可以通过 l:属性来只改本地属性。相当于我们使用了:setlocal命令。

:let还可以通过@来访问寄存器。
还记得吗?d,c,y等命令支持将删除或复制的内容放到寄存器中,如果未指定,则放入""寄存器中。"0到"9中最储历史值。还有"a到"z一共26个命名寄存器。

首先是数据类型,Vimscript提供下面9种基本数据类型:

Number: 32位带符号整数. 如果支持+num64,就是64位带符号整数。支持十六进制,二进制和八进制。 Float: 浮点数。只有编译时支持+float才有。 String: 字符串。 List: 有序列表。 Dictionary: 哈希表。 Funcref: 函数引用。

特殊值

v:false v:true v:none v:null
数字和字符串

在Vimscript中,字符串和数字之间会进行自动转换。我们看下官方的几个例子:

String "456" -- Number 456 String "6bar" -- Number 6 String "foo" -- Number 0 String "0xf1" -- Number 241 String "0100" -- Number 64 String "0b101" -- Number 5 String "-8" -- Number -8 String "+8" -- Number 0

"foo"被转换成0,和"+8"被转换成0这两条case要特殊注意。

另外,八进制"0100"的情况也要特别注意。
为了避免出现八进制转换的问题,我们可以使用str2nr函数来做显示转换。因为str2nr默认是10进制的。

echo 0100

的结果为64

echo str2nr("0100")

的值为100.

真值和假值

在Vimscript中,0表示假值,其余数值均表示真值。假值也可以用v:false表示,真值为v:true.

比如"foo"的值为假,因为"foo"转换成整数的值是0.

Vimscript的列表可以混杂各种元素。

例:

:let b:list1 = [1, 4.1e+3, "Hello",[1,2]]

列表可以用下标访问。比如b:list1[0].
列表的下标从0开始计数。而[-1]表示最后一个元素。

如果要给列表元素一个不存在时的默认值的话,可以使用get()函数。

例:

 :echo get(mylist, idx)

 :echo get(mylist, idx, "NONE")

两个列表可以通过+号来连接成一个列表:

 :let longlist = mylist + [5, 6]

 :let mylist += [7, 8]

Vimscript取子列表跟其它脚本语言很像,用[起始位置:结束位置]来进行切片。

 :let shortlist = mylist[2:-1] " get List [3, "four"]

如果是从第一个元素开始,或者到最后一个元素结束,都可以省略:

 :let endlist = mylist[2:] " from item 2 to the end: [3, "four"]

 :let shortlist = mylist[2:2] " List with one item: [3]

 :let otherlist = mylist[:] " make a copy of the List

如果越界了,也不会产生错误,到最后一个元素结束了就是了么。

 :let mylist = [0, 1, 2, 3]

 :echo mylist[2:8] " result: [2, 3]
列表的赋值和拷贝

如果将一个列表赋给另一个变量,不会复制列表,只是传递引用。
如果想要复制一份列表的话,需要使用copy函数。
例:

 :let aa = [[1, a], 2, 3]

 :let bb = copy(aa)

 :call add(aa, 4)

 :let aa[0][1] = aaa

 :echo aa

 [[1, aaa], 2, 3, 4]

 :echo bb

 [[1, aaa], 2, 3]

但是请注意,copy只是浅copy,如果有子列表,是只复制引用的。如果真的要大搬家,需要使用deepcopy()函数。

列表的比较 is: 比较两个变量是否引用同一列表 ==:比较两个列表的值是否相等

另外需要注意的是,对于变量,会自动将字符串转成数字,但是对于列表中的元素,没有这种自动转换。

 echo 4 == "4"

 echo [4] == ["4"]

 0
列表的多变量赋值

如果要引用列表中的值,可以同时将其赋给多个变量。
例:

 :let [var1, var2; rest] = mylist

等价于:

 :let var1 = mylist[0]

 :let var2 = mylist[1]

 :let rest = mylist[2:]

这个对于函数返回值之类的是个利好。

列表的修改

对于可以定位的值,直接通过:let赋值的方式修改。

对于插入,添加,删除等,使用相关函数来进行操作:

 :call insert(list, a) " prepend item a

 :call insert(list, a, 3) " insert item a before list[3]

 :call add(list, "new") " append String item

 :call add(list, [1, 2]) " append a List as one new item

 :call extend(list, [1, 2]) " extend the list with two more items

 :let i = remove(list, 3) " remove item 3

 :let l = remove(list, 3, -1) " remove items 3 to last item

 :call filter(list, v:val !~ "x") " remove items with an x

列表还可以排序、反转和排重:

 :call sort(list) " sort a list alphabetically

 :call reverse(list) " reverse the order of items

 :call uniq(sort(list)) " sort and remove duplicates
使用for循环来处理列表

for循环是处理列表的最简用手段:

 :for item in mylist

 : call Doit(item)

 :endfor

for循环支持解构式的赋值:

 :for [i, j; rest] in listlist

 : call Doit(i, j)

 : if !empty(rest)

 : echo "remainder: " . string(rest)

 : endif

 :endfor
列表常用函数 empty函数:判空 len函数:计算列表元素个数 max函数:求列表最大元素 min函数:求列表最小元素 count函数:计算元素在列表中出现的次数 index函数:求元素第一次出现的位置 split函数:将字符串拆分成列表 join函数:将列表连接成一个字符串

Vimscript的字典功能,其实就是哈希表。

例:

 :let mydict = {1: one, 2: two, 3: three}

 :let emptydict = {}

访问字典可以使用[]:

 :let val = mydict["one"]

 :let mydict["four"] = 4

在没有歧义的情况下,也可以使用.:

 :let val = mydict.one

 :let mydict.four = 4

可以通过遍历keys列表和values列表的方式来遍历字典。

例:

 :for key in keys(mydict)

 : echo key . :  . mydict[key]

 :endfor

 :for v in values(mydict)

 : echo "value: " . v

 :endfor

还可以遍历前先排一次序:

 :for key in sort(keys(mydict))

也可以将key和value打包在一起,使用item函数遍历:

 :for [key, value] in items(mydict)

 : echo key . :  . value

 :endfor
字典的复制

字典的复制也同样要使用copy和deepcopy函数。

字典的增删改查

字典的修改和增加都很简单,直接赋值就是了:

 :let dict[4] = "four"

 :let dict[one] = item

教程 | Vim 教程【命令-操作-快捷键】 命令历史以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令。 启动vim在命令行窗口中输入以下命令即可 vim 直接启动vim vim filename 打开vim并创建名为filename的文件 文件命令打开单个文件 vim file 同时打开多个文件 vim file1 file2 file3 ... 在vim窗口中打开一个新文件 :open file 在新窗口中打开文件 :split file 切换到下一个文件 切换到上一个文件 查看当前打开的文件列表,当前正在编辑的文件会用[]括起来。
Vim技能修炼教程(15) - 时间和日期相关函数 前面我们走马观花地将Vimscript的大致语法过了一遍。下面我们开始深入看一下Vimscript都给我们准备了哪些武器。如果只用这些武器就够了,那么就太好了,只用Vimscript会导致最佳的兼容性。否则不管是用:python还是使用扩展库,都给可移植性带来麻烦。
lusing 刘子瑛,阿里系统框架专家。工作十余年,一直对新编程语言、新开发方法、数学与算法相关和并发等相关领域保持浓厚的兴趣。乐于通过技术分享促进新技术。