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

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
  • Job: 任务相关
  • Channel: 通道相关

一个变量的类型可以通过type()函数查看。

数字和字符串

在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"
        1
        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
时间: 2024-08-11 18:43:49

Vim技能修炼教程(13) - 变量的相关文章

Vim技能修炼教程(1) - 使用vundle管理插件

世界上有两个伟大的编辑器:一个是emacs,一个是vi.它们从诞生以来,一直在Unix/Linux世界得到最广泛的支持. 尽管过了几十年,在Windows平台上和跨平台上有层出不穷的后起之秀不断挑战它们的地位,比如编辑器界的Sublime Text,Ultra Editor,Notepad++,pspad,Atom,Visual Studio Code,IDE界的Eclipse, IntellJ IDEA, NetBeans等等,但是它们的地位从未动摇过. 写C#的最好IDE一定是Visual

Vim技能修炼教程(2) - 语法高亮速成

语法高亮速成 我们继续在人间修行Vim技能之旅.上一次我们学习了如何通过vundle安装插件,这次我们迅速向写插件的方向挺进. 我们先学习一个最简单的语法高亮插件的写法. 语法高亮基本上是由三部分组成: 配色方案 正则表达式 配色方案和正则表达式的规则对应关系 简单的三步法写语法高亮 第一步,写匹配的正则表达式 我们举个最简单的例子,以Android的log为例,Android的log格式如下: --------- beginning of system 05-05 17:55:48.909 I

Vim技能修炼教程(10) - 代码跳转

程序员功能 前面我们用了5讲的篇幅来讲基本编辑的基本功:第4讲是基本操作,第5讲是操作符,第6讲行编辑ex命令,第7讲可视模式,第8讲多窗口,第9讲缓冲区和标签页. 从这一讲开始,我们从通用功能向程序员常用功能挺进.首先我们从浏览代码最常用的跳转功能开始. 代码跳转 代码跳转,需要传说中的Exuberant Ctags工具,地址在:http://ctags.sourceforge.net/. 当然大家根据系统不同各显神通吧.比如我是macOS,就通过Homebrew来安装了.大家手头有什么"ap

Vim技能修炼教程(6) - 行编辑器

在很久很久以前,计算机的运算能力还很弱,终端与主机的通信也不好.在没有显示器的时代,只能通过电传打字机跟主机通信.那时候只有行编辑器,编辑的时候只能在一行中进行.需要显示哪一行,就把哪一行或者哪几行打印出来看. Unix上使用的行编辑器是ed. 这个编辑器至今仍然在Unix/Linux/FreeBSD各系统中存在. ed的增强版是ex. ex最大增强之处就是提供了可以全屏编辑的模式.在ex中输入:visual命令,就会切换到全屏编辑模式.好吧,这就是vi.Vi本质上就是ex编辑器的visual模

Vim技能修炼教程(3) - 语法高亮进阶

语法高亮进阶 首先我们复习一下上节学到的三个命令: syntax match用于定义正则表达式和规则的对应 highlight default定义配色方案 highlight link将正则规则和配色方案对应起来 但是,定义好了规则,如何让它自动生效呢?我们需要识别文件类型. 识别文件类型 我们创建一个新插件,建立一个ftdetect目录,然后为这个类型创建一个vim文件,比如之前logcat的例子,我们就建立一个logcat.vim. 例子我们还是找github上的:https://githu

Vim技能修炼教程(8) - 多窗口

多窗口 如果一个vim只能开一个窗口,那肯定是有点low.尤其是写代码的时候,打开多个文件是经常的需求. 速成教程 横着切成两个 :split 文件名 上下切换窗口 Ctrl-W加上上下键,可以实现上下切换窗口. 关掉一个窗口 跟退出vi一样.比如正常模式下的ZZ,再比如:q. 竖着切成两个 :vsplit 文件名 左右切换窗口 Ctrl-W加上左右键 循环切换窗口 Ctrl-W w 好了,欢迎进入多窗口的世界.基本功能就这么多,大家先把多窗口用起来吧. 再学一点 分割窗口 打开只读文件并水平分

Vim技能修炼教程(17) - 编译自己的Vim

编译自己的Vim 前面我们已经对Vim有比较丰富的了解了.我们也知道Vim有很多编译时的选项,很多功能依赖于这些编译选项.其中最重要的就是脚本语言的支持,很多发行版本是不全的.为了支持我们所需要的功能,我们需要编译自己的Vim. 首先我们要下载Vim的源代码: git clone https://github.com/vim/vim.git Linux上编译Vim 以Ubuntu为例,首先要安装一些库的开发包,例: sudo apt-get install libncurses5-dev lib

Vim技能修炼教程(16) - 浮点数计算函数

浮点数计算函数 这一节的所有函数,只有在vim编译时支持了+float时才有效. 三角函数 sin() : sine正弦函数 cos() : cosine余弦函数 tan() : tangent正切函数 asin() : arc sine反正弦函数 acos() : arc cosine反余弦函数 atan() : arc tangent反正切函数 atan2({X坐标},{Y坐标}) : arc tangent反正切函数 sinh() : hyperbolic sine 双曲正弦函数 cosh

Vim技能修炼教程(15) - 时间和日期相关函数

Vimscript武器库 前面我们走马观花地将Vimscript的大致语法过了一遍.下面我们开始深入看一下Vimscript都给我们准备了哪些武器.如果只用这些武器就够了,那么就太好了,只用Vimscript会导致最佳的兼容性.否则不管是用:python还是使用扩展库,都给可移植性带来麻烦. 随着Vim的广泛移植,Vimscript带来的可移植性还是很可观的.这是一门跨相当多平台可用的语言. 之前我们为了区分normal命令和ex命令,在脚本中使用ex命令的前面都加上了":"前缀.从这