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

Vim scriptで, has_keyではなくgetを使うと遅くなることがある

Vim

Vimを使っているあなたは、Vim scriptを毎日書かれているのではないかなと思います。
Vim scriptには様々な関数がありますが、最初にgetという関数を知った時は、「なんて便利なんだ!!!」と思われたのではないでしょうか。


例えば、値段の辞書と、値段を返す関数があって、値段の情報がなければ-1を返しなさいと言われたら

let s:price = { 'apple': 100 }
function! Get_price(fruit)
  if has_key(s:price, a:fruit)
    return s:price[a:fruit]
  endif
  return -1
endfunction

と最初は書きますが、getを使うと

let s:price = { 'apple': 100 }
function! Get_price(fruit)
  return get(s:price, a:fruit, -1)
endfunction

と出来ます。


そうです。
この三つ目の引数がとれることが、めちゃくちゃ便利なんですよ!


getはリストを引数に取ることもできるので、可変長の引数を処理するのにも便利です。

function! Func(...)
  let x = get(a:000, 0, 'hello')
  let y = get(a:000, 1, 20)
endfunction

なんか大抵のコードはgetで書ける気がしてきます。



しかし... 最近、getは良くないなってケースに気が付きました。
こういう場合です。

function! Test()
  " ...
  let x = get(dict, key, s:heavy_func())
  " ...
endfunction

function! s:heavy_func()
  " なんか重い処理
  return y
endfunction

こういう場合、dict[key]が存在しても、s:heavy_funcは呼ばれてしまいます。
s:heavy_funcが時間が掛かる関数だと、損なのです。


そういう時は、has_keyを使いましょう。

function! Test()
  " ...
  let x = has_key(dict, key) ? dict[key] : s:heavy_func()
  " ...
endfunction

三項演算子だと、条件式が真の時に偽の式は評価されないので、ハッピーです。
(文字列結合の.演算子使ってても、大丈夫...ですよね?)



getの三つ目の引数が重い処理の時は気をつけましょうという話でした。