Humane VimScript:最小限のオブジェクト指向

VimScriptは非常に友好的ではありませんが、予想外に強力な言語であることがわかりました。 幸いなことに、彼を友達にすることは可能です。これは、この一連の記事で行うことをお勧めします。 ここでは、オブジェクト指向のパラダイムを使用した典型的なVimScriptの問題の解決策をいくつか見ていきますが、この言語の基本については触れません。 おそらく、この記事は、私たちになじみのあるソリューションの非標準の実装に興味があるプログラマーにとっても興味深いものになるでしょう。








オブジェクトの向きは最小限に



おそらく、VimScriptに関する私の記事を既に読んでいて、 vim_libライブラリを調べている人がいるかもしれませんが、便利で使いやすいですか? 真実ではない ! 「コードの匂い」が目を痛め、読めないことがあります。 弱い「におい」でさえ、「より良く」、「より正確に」、「より簡単に」したいという欲求を抑えられません。 幸いなことに、それは難しいことではなく、すべてをさらに簡素化するのに十分であり、私は成功しましたが、今はそれについてではありません。 この一連の記事では、特定のタスクのテンプレートソリューション(必要に応じてパターン)のみを提供し、新しいライブラリを発明しません。



VimScriptでObjectクラスを使用して1年以上の間、「ダニのコード」が含まれていると確信していましたが、これは安全に削除できます。 「そのような匂い」が出たら、すべてを単純化する時が来たということです。 特に、VimScriptでオブジェクト指向モデルを実装する際に安全に拒否できるもの:





「クラスなしでオブジェクト指向モデルを実装する方法は?」 -すべてが非常に簡単です。 これを行うには、コンストラクターと呼ばれるオブジェクトのタイプごとに1つの関数が必要です。 この関数は、目的の構造を持つ初期化されたオブジェクトを作成して返します。 JavaScriptを思い出させますよね? 完成したフォームでは次のようになります。



基本クラス
let s:Parent = {} function! s:Parent.new(a) dict return extend({'a': a:a}, s:Parent) endfunction function! s:Parent.setA(a) dict let l:self.a = a:a endfunction function! s:Parent.getA() dict return l:self.a endfunction let s:pobj = s:Parent.new('foo') echo s:pobj.getA() " foo
      
      







クラス全体を実装する4行のコード。 このソリューションは、新しい辞書を初期化し、プロトタイプメソッドを使用して(extend関数を使用して)拡張することになります。



次に、コンストラクターと親クラスのメソッドの1つをオーバーライドして、継承の実装を検討します。



子クラス
 let s:Child = {} function! s:Child.new(a, b) dict return extend(extend({'b': a:b}, s:Parent.new(a:a)), s:Child) endfunction function! s:Child.setB(b) dict let l:self.b = a:b endfunction function! s:Child.getB() dict return l:self.b endfunction function! s:Child.getA() dict return call(s:Parent.getA, [], l:self) . l:self.b endfunction
      
      







合計で、コンストラクターは別のextend関数の呼び出しによって補完されます。これにより、最初に親クラスのオブジェクトでベースディクショナリーを展開し、次にプロトタイプ(子クラス)のメソッドで展開できます。 同様に、オーバーライドメソッドから親メソッドを呼び出すことも、call関数を使用して非常に簡単です(JavaScriptでの適用に似ています)。



新しい継承呼び出しを追加せずに、さらに継承が実装されます。



さらなる継承
 let s:SubChild = {} function! s:SubChild.new(a, b, c) dict return extend(extend({'c': a:c}, s:Child.new(a:a, a:b)), s:SubChild) endfunction
      
      







ミックスイン



注意深い読者は、ここで複数の継承が実装されていることをすでに推測しているため、ミックスインを使用できます。



さらなる継承
 let s:Publisher = {} function! s:Publisher.new() dict return extend({'listeners': {}}, s:Publisher) endfunction let s:Class = {} function! s:Class.new() dict return extend(extend({}, s:Publisher.new()), s:Class) endfunction
      
      







インターフェース



ポリモーフィズムはオブジェクト指向のパラダイムの非常に重要な部分であり、特に必要なプラグインがいくつかあるため、無視できませんでした。 それを実現するには、instanceofメソッドがクラスのセマンティクスを評価するために必要です。 彼に必要なのは、ターゲットクラスで宣言されたメソッドがオブジェクトに存在するかどうかを確認することです。存在する場合は、このクラスのインスタンスと見なすことができます。 なぜプロパティではなくメソッドなのか? メソッドを介してオブジェクトを操作することに同意したからです。 これはいわゆるダックタイピングです。



instanceof
 function! s:instanceof(obj, class) for l:assertFun in keys(filter(a:class, 'type(v:val) == 2')) if !has_key(a:obj, l:assertFun) return 0 endif endfor return 1 endfunction echo s:instanceof(s:childObject, s:Parent) " 1 echo s:instanceof(s:childObject, s:SubChild) " 0
      
      







このような優れた機能を備えているため、将来のクラスのセマンティクスを定義するインターフェイスを実装することは難しくありません。



インターフェースの例
 let s:Iterable = {} function! s:Iterable.valid() dict endfunction function! s:Iterable.next() dict endfunction function! s:Iterable.current() dict endfunction let s:Iterator = {} function! s:Iterator.new(array) dict return extend(extend({'array': a:array, 'cursor': 0}, s:Iterable), s:Iterator) endfunction function! s:Iterator.valid() dict return exists('l:self.array[l:self.cursor]') endfunction function! s:Iterator.next() dict let l:self.cursor += 1 endfunction function! s:Iterator.current() dict return l:self.array[l:self.cursor] endfunction let s:iterator = s:Iterator.new([1,2,3]) echo s:instanceof(s:iterator, s:Iterable) " 1
      
      







オブジェクトは、インスタンスではなくインターフェイスクラスによって展開されることを覚えておくことが重要です。 ただし、他の言語と同様。



JSONは簡単です!



一部の人にとっては、これは啓示になりますが、JSONはVimScriptのいとこです! 信じられない? 私はあなたにそれを証明します:



ジョンソン
 let s:childObj = s:Child.new(1, 2) let s:json = string(filter(s:childObj, 'type(v:val) != 2')) echo s:json " {'a': 1, 'b': 2} echo eval(s:json) == s:childObj " 1
      
      







さようなら



この記事があなたの興味を引き、この素晴らしいエディタを試してみることをお勧めします。 もしそうなら、私は次の記事であなたの人生を楽にします。




All Articles