2013-11-13

Vim中級者を脱する スコープ編

個人的に、Vimで一番ハマったのがスコープの問題でした。

vimrcのコピペばかりの、あなた。

せめて、よく登場するスコープだけでも理解してみましょう。

よく見るスコープ一覧

  • グローバルスコープ g:
  • 関数内スコープ a:
  • スクリプトスコープ s:
  • バッファスコープ b:
  • 接頭辞なし let huga=...など

グローバル(g:)スコープ

どこからでも参照できます。

プラグインの設定で見慣れたスコープですね。

let g:neocomplete#enable_at_startup = 1

変数を初期化するには、次のようにします。 大量のエラーコードによって操作できなくなるので、嫌いな人のvimrcの末尾に書き込んでください。

for key in keys(g:)
  execute 'unlet g:' . key
endfor

関数内(a:)スコープ

関数内で、引数を参照するときに使用するスコープ

個人的に一番理解しがたいスコープです。

こんな感じで使います。他言語から移ってきた人には、正直使いづらい。

function! Huga(first, second)
  echo a:first
  "=> 'a'

  echo a:
  "=> {'0': 0, '000': [], 'second': 'b', 'first': 'a', 'firstline': 5, 'lastline': 5}
endfunction

call Huga('a', 'b')

「あーなるほど、関数内でだけ有効なスコープなのか。

と、思っていたらそれは間違い。

下記のようにすると、グローバルスコープとして参照できます。

function! a:huga()
  echo 'Global!?!?!?'
endfunction

call a:huga() " => Global!?!?!?

実は、これ関数名に:が許可されているだけです。 なので実際はa:スコープは関係ないんだけど、分かりづらい。

スクリプト(s:)スコープ

ファイル内でのみ有効なスコープです。

プラグインで、プライベートなメソッドや定数を作るときによく使います。

let s:script_scope = '外部からは参照できない'
function! s:script_scope_method()
  " プライベートメソッドとしてよく使われる
endfunction

このs:は、スクリプトがsourceされるときに置き換えられ、<SNR>1_...という感じの形になります。

えぇ、そうです。すると、グローバルなスコープとして参照できます。

この<SNR>の後にどの数値が割り振られているかは、:scriptnamesで参照できます。

また、s:<SID>として使えばスコープを超えて使用できるようになります。

マッピングの時に、scriptスコープを使う時などは必須ですね。

nnoremap s :echo &lt;SID&gt;SID()&lt;CR&gt;

ただし、変数は基本的には聖域です。

バッファ(b:)スコープ

バッファ単位のスコープです。

ファイルタイプによる設定や、一時バッファによる変数などに使います。

  • ファイルタイプの変更で、b:current_syntaxなどが初期化&格納されます
  • Uniteを起動で、b:uniteにデータが格納されます。

Uniteのデバッグするときには、echo b:unite.candidatesなどを参照しましょう。

あぁ、ようやくまともなスコープだ。

接頭辞なし(let huga=)変数

えぇ。グローバルなスコープです。

お前もか!

マナーとしては、やはりg:で宣言したいところですが、

Vimにデフォルトで入っているプラグインは、容赦なくこの変数を使ってきます。

:echo loaded_*<Tab>などすれば、奴らを見つけられるはずです。

細かいことを言えば、関数内ならばローカルスコープです。。。

スコープのまとめ

  • スコープはほとんどグローバルで参照できる
  • VimLは枠にハマらない素敵な言語仕様を持っている
  • getbufvar()などでスコープへアクセス出来るため、聖域はほとんど無い

正直今でも理解出来ていない。