この広告は、90日以上更新していないブログに表示しています。
毎日Vim scriptを書いているあなたは、exists関数をよく用いると思います。特に、ユーザーが設定する変数があるかないかで挙動を制御するのに便利ですよね。
existsは、コードを書くときには分かりやすいです。「何某が存在するときはこうで…」と言いながらコードを書けるからです。しかし多くの場合、変数名を繰り返してしまうという問題があります。そういう場合は、get関数を使いましょう。(同じ趣旨の記事は、vim-jp » Hack #239: グローバル変数を安全に参照する があります)
例えば次のようなケースです。
syntaxm4
letb:m4_quote=exists('g:m4_default_quote') ?g:m4_default_quote :"`,'"
これは
letb:m4_quote=get(g:,'m4_default_quote',"`,'")
と書くことができます。変数名の繰り返しがなくなって、綴りを間違えたりすることもなくなりますね。「同じ事を繰り返すな」そういうふうに幼稚園で習ったはずです。
次のケースは多いのか少ないのか分かりませんが、検索すると幾つか出てきます。existsで調べた変数と、andかorを取るケースです。例えば
vinarise
ifexists('g:vinarise_no_default_keymappings')&& \g:vinarise_no_default_keymappings
vim-surround
if !exists("g:surround_no_mappings")|| !g:surround_no_mappings
syntastic
if !exists('g:syntastic_enable_perl_checker')|| !g:syntastic_enable_perl_checker
こういうケースですね。これらは、次のようにget関数を用いることができます。
vinarise
ifget(g:,'vinarise_no_default_keymappings')
vim-surround
if !get(g:,'surround_no_mappings')
syntastic
if !get(g:,'syntastic_enable_perl_checker')
変数が存在した時に、もう少し違う条件を課す場合があります。例えば
unite-outline
ifexists('g:unite_source_outline_ctags_program')&& !empty(g:unite_source_outline_ctags_program)
これをgetで書くと
unite-outline
if !empty(get(g:,'unite_source_outline_ctags_program'))
となります。変数が存在しないときは、 !empty(0) == 0 だからです。
また、次のようなケースもありました。
autodate
ifexists('b:autodate_keyword_pre')&&b:autodate_keyword_pre!=''
これは
ifget(b:,'autodate_keyword_pre','')!=''
同じくautodate
ifexists('b:autodate_lines')&&b:autodate_lines>0
は
ifget(b:,'autodate_lines')>0
と書けます。
さて、以上、幾つかのケースを見てきますと、公式を作りたくなってきます。まず、一番最初の三項演算子のパターン
syntaxm4
letb:m4_quote=exists('g:m4_default_quote') ?g:m4_default_quote :"`,'"==letb:m4_quote=get(g:,'m4_default_quote',"`,'")
のパターンは
exists('g:foo') ?g:foo :bar==get(g:,'foo', bar)
と書けます。g:はb:でもs:でも可能です。このパターンは、街頭の女子高生46人に投票していただいた結果、getで書き直して欲しいコードのナンバーワンという結果が出ています。
次に、
vinarise
ifexists('g:vinarise_no_default_keymappings')&& \g:vinarise_no_default_keymappings==ifget(g:,'vinarise_no_default_keymappings')
のパターンは
exists('g:foo')&&g:foo==get(g:,'foo')
となります。get()の3つ目の引数を省略すると0になるからです。
更に
vim-surround
if !exists("g:surround_no_mappings")|| !g:surround_no_mappings==if !get(g:,'surround_no_mappings')
は
!exists('g:foo')|| !g:foo== !get(g:,'foo')
ですね。一つ前の公式の否定形です。
そして
ifexists('b:autodate_keyword_pre')&&b:autodate_keyword_pre!=''==ifget(b:,'autodate_keyword_pre','')!=''
のようなケース。これは少し難しいですね。ある関数fがあって、
exists('g:foo')&& f(g:foo)== f(get(g:,'foo', bar))(ここでbarは f(bar)==0 となる値)
となります。先程のもう一つのautodateの例は
ifexists('b:autodate_lines')&&b:autodate_lines>0==ifget(b:,'autodate_lines', bar)>0(ここでbarは bar>0==0 となる値 → つまり0 や-1 など)==ifget(b:,'autodate_lines',0)>0==ifget(b:,'autodate_lines')>0
と変形できます。なぜなら、0 > 0 は 0 だからです。
以上、4つのパターンを見てきました。
(a)
exists('g:foo') ?g:foo :bar==get(g:,'foo', bar)
(b)
exists('g:foo')&&g:foo==get(g:,'foo')
(c)
!exists('g:foo')|| !g:foo== !get(g:,'foo')
(d)
exists('g:foo')&& f(g:foo)== f(get(g:,'foo', bar))(ここでbarは f(bar)==0 となる値)
他に、少し珍しくはなりますが、次のパターンも考えられます。
(e)
exists('g:foo')&& !g:foo== !get(g:,'foo',1)
(f)
!exists('g:foo')||g:foo==get(g:,'foo',1)
このパターンを使ったものは、使用例は少ないですが、次のようなコードが見つかりました。
vim-surround
ifexists("b:surround_indent") ?b:surround_indent :(!exists("g:surround_indent")|| g:surround_indent)
これを、以上で作った公式を用いて変形してみます。
vim-surround
ifexists("b:surround_indent") ?b:surround_indent :(!exists("g:surround_indent")|| g:surround_indent)==ifget(b:,'surround_indent', !exists("g:surround_indent")|| g:surround_indent)==ifget(b:,'surround_indent', !get(g:,'surround_indent',1))
変形出来ました。
公式がいっぱいあるように見えますが、(c)は(b)の否定ですし、(f)は(e)の否定です。そして(b)も(e)も、(d)の特殊ケースとなっていますので、実質的には(a)と(d)だけですね。本質が見えてしまえば式変形も簡単です。
変数をexistsで調べているコードは、getで書けることが多いです。また、andやorで変数名が繰り返しになっている場合、getで書くとすっきりします。ただ、人によってはgetを使ったコードは見難い、すぐに理解できないと思います。他の人やあなた自身が困ることになりますので、技巧的なgetの使用は控えましょう。
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。