読者です 読者をやめる 読者になる 読者になる

単独eval読書会#01

vim

vimscriptを書くためにはhelpを引かないといけないのですが,
丁寧に解説しているサイトが少ないので自分で書いてみました.
:help evalを理解できるようになれば,きっとvimscriptすらすら書くようになれるはずです.


:help evalは組み込み関数の一覧が種類別に分類されてなくabc順に列挙してあるので大変不親切だと思います.
そのうち分類別に書いてみようと思います.

追記: :help function-listを参照すると機能別に分類されているようです(thincaさんより).


第一回は変数の概要です.なお想定しているvimのバージョンは7.3です.

変数の型

全部で6種類あります.

echo 12
" 12 (数値)
echo 1.0
" 1.0 (浮動小数点数)
echo 'hello'
" hello (文字列)
echo function("strlen")
" strlen (関数への参照)
echo ['a', 3]
" ['a', 3] (リスト)
echo {'a':'foo', 'b':'bar'}
" {'a': 'foo', 'b': 'bar'} (辞書)

なお数値と文字列は文脈により暗黙に変換される場合があります.
なお変数の宣言・再定義にはletを必ず使用し,変数の破棄にはunletを用います.

" 宣言
let a = 12
echo a
" 12

" 再度定義可能
let a = 13
echo a
" 13

" 変数の破棄
unlet a
echo a
" E121: Undefined variable: a
" E15: Invalid expression: a

" letを付けないとエラー
b = 12
" E94: No matching buffer for = 12

再定義の際に型が異なるとエラーを吐く可能性があります.
エラーにならないようにするには,一旦unletする必要があります.

" 整数 - 浮動小数点数
let a = 12
let a = 12.5  " OK
let a = 12    " OK
unlet a

" 整数 - 文字列
let a = 12
let a = 'foo' " OK
let a = 12    " OK
unlet a


" 文字列 - 浮動小数点数
let a = '12.5'
let a =  12.5  " E706: Variable type mismatch for: a
unlet a

let a =  12.5
let a = '12.5' " E706: Variable type mismatch for: a
unlet a

" 文字列 - リスト
let a = 'hello'
let a = ['foo', 'bar'] " E706: Variable type mismatch for: a

スコープ

オプションを設定する際にsetとsetlocalで挙動が異なるように,変数にもスコープがあります.

let g:foo = 0

function! Foo()
  let l:foo = 1
  let g:foo = 1
  echo "Foo() l:foo = " l:foo ", g:foo = " g:foo
endfunction

function! Bar()
  let l:foo = 2
  let g:foo = 2
  echo "Bar() l:foo = " l:foo ", g:foo = " g:foo
  call Foo()
  echo "Bar() l:foo = " l:foo ", g:foo = " g:foo
endfunction

call Bar()
" Bar() l:foo =  2 , g:foo =  2
" Foo() l:foo =  1 , g:foo =  1
" Bar() l:foo =  2 , g:foo =  1

例では関数ローカル変数l:fooとグローバル変数g:fooの挙動の違いを示しています.

スコープの種類は以下の通りです.

無し 関数内では関数ローカル,それ以外ではグローバル
b バッファローカル
w ウィンドウローカル
t タブローカル
g グローバル
l 関数ローカル
s スプリクトローカル
a 関数の引数
v Vimがあらかじめ定義した変数

グローバル変数は使用しないようにするのが良いでしょう.
vimscriptを書く場合でも極力スクリプトローカルな変数を使用するようにします.

オプション変数

setやsetlocalを用いて設定する変数を参照・再定義する場合,頭に&を付けて呼び出します.

set      tabstop=2
setlocal tabstop=4

echo tabstop
" E121: Undefined variable: tabstop
" E15: Invalid expression: tabstop
echo &tabstop
" 4 (local優先)
echo &g:tabstop
" 2 (global参照)
echo &l:tabstop
" 4 (local参照)

これらの変数にもスコープが存在します.

その他

変数が存在するかどうかを調べるにはexistsを使用します.

let a = 12

" existsの引数は文字列にすること
" このように呼び出すとaの値(この場合は12)という変数を参照しようとする
" もちろん12という変数は存在しないので0が返る
echo exists(a)
" 0

" こちらの書き方がが正しい
echo exists('a')
" 1

unlet a
" aを破棄したのでもう存在しない
echo exists('a')
" 0

変数の型を調べるにはtypeを使用します.

let list = [1, 2, [3, 4]]

" NOTE: typeで比較する場合,マジックナンバーを直接記述しない

echo type(list) == type(0)
" 0 (リストと数値を比較)
echo type(list) == type([])
" 1 (リストとリストを比較)

echo type(1)    == type(1.0)
" 0 (整数と浮動小数点数を比較)

整数と浮動小数点数の型は異なるようです.