Untuk menjawab pertanyaan Anda: prototipe call()
dalam manual adalah call({func}, {arglist} [, {dict}])
; yang {arglist}
argumen perlu harfiah objek Daftar, tidak daftar argumen. Artinya, Anda harus menulis seperti ini:
let @x = call(a:functionToExecute, [GetSelectedText()])
Asumsi ini a:functionToExecute
adalah Funcref (lihat :help Funcref
), atau nama fungsi (yaitu string, seperti 'Type1ProcessString'
).
Nah, itu fitur hebat yang memberi Vim semacam kualitas seperti LISP, tetapi Anda mungkin jarang menggunakannya seperti di atas. Jika a:functionToExecute
adalah string, nama fungsi, maka Anda dapat melakukan ini:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
dan Anda akan memanggil pembungkus dengan nama fungsi:
call Wrapper('Type1ProcessString')
Jika di sisi lain a:functionToExecute
adalah Funcref, Anda dapat memanggilnya langsung:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
tetapi Anda perlu memanggil pembungkus seperti ini:
call Wrapper(function('Type1ProcessString'))
Anda dapat memeriksa keberadaan fungsi dengan exists('*name')
. Ini memungkinkan trik kecil berikut:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
yaitu fungsi yang menggunakan built-in strwidth()
jika Vim cukup baru untuk memilikinya, dan jatuh kembali ke strlen()
sebaliknya (saya tidak berpendapat bahwa mundur seperti itu masuk akal; saya hanya mengatakan itu bisa dilakukan). :)
Dengan fungsi kamus (lihat :help Dictionary-function
) Anda dapat menentukan sesuatu yang menyerupai kelas:
let g:MyClass = {}
function! g:MyClass.New(...)
let newObj = copy(self)
if a:0 && type(a:1) == type({})
let newObj._attributes = deepcopy(a:1)
endif
if exists('*MyClassProcess')
let newObj._process = function('MyClassProcess')
else
let newObj._process = function('s:_process_default')
endif
return newObj
endfunction
function! g:MyClass.getFoo() dict
return get(get(self, '_attributes', {}), 'foo')
endfunction
function! g:MyClass.setFoo(val) dict
if !has_key(self, '_attributes')
let self._attributes = {}
endif
let self._attributes['foo'] = a:val
endfunction
function! g:MyClass.process() dict
call self._process()
endfunction
function! s:_process_default()
echomsg 'nothing to see here, define MyClassProcess() to make me interesting'
endfunction
Maka Anda akan instantiate objek seperti ini:
let little_object = g:MyClass.New({'foo': 'bar'})
Dan sebut metode-metodenya:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
Anda juga dapat memiliki atribut dan metode kelas:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(perhatikan tidak perlu untuk di dict
sini).
Sunting: Subclassing adalah sesuatu seperti ini:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
Titik halus di sini adalah penggunaan copy()
bukan deepcopy()
. Alasannya adalah untuk dapat mengakses atribut dari kelas induk dengan referensi. Ini bisa dicapai, tetapi sangat rapuh dan membuatnya benar jauh dari sepele. Masalah lain yang potensial adalah bahwa jenis conflates subclass is-a
dengan has-a
. Untuk alasan ini atribut kelas biasanya tidak terlalu sepadan dengan rasa sakitnya.
Ok, ini sudah cukup untuk membuatmu berpikir.
Kembali ke cuplikan kode awal Anda, ada dua detail yang dapat diperbaiki:
- Anda tidak perlu
normal gvd
menghapus pilihan lama, normal "xp
akan menggantinya bahkan jika Anda tidak membunuhnya terlebih dahulu
- gunakan
call setreg('x', [lines], type)
sebagai ganti let @x = [lines]
. Ini secara eksplisit menetapkan jenis register x
. Kalau tidak, Anda mengandalkan x
sudah memiliki jenis yang benar (yaitu characterwise, linewise, atau blockwise).
dict
kata kunci. Ini berlaku untuk "metode kelas" Anda. Lihat:h numbered-function
.