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
.dict
apa punMyClass
). Tapi saya merasa itu membingungkan, jadi saya cenderung menambahkandict
secara eksplisit.dict
untuk metode objek, tetapi tidak untuk metode kelas, untuk membantu memperjelas maksud Anda?self
berbeda untuk metode kelas dan untuk metode objek - itu adalah kelas itu sendiri dalam kasus sebelumnya, dan contoh dari objek saat ini di yang terakhir. Untuk alasan ini saya selalu merujuk ke kelas itu sendirig:MyClass
, tidak pernah menggunakanself
, dan saya kebanyakan melihatdict
sebagai pengingat bahwa itu ok untuk digunakanself
(yaitu, fungsi yangdict
selalu bertindak pada instance objek). Lagi-lagi, saya tidak menggunakan metode kelas banyak, dan ketika saya melakukannya saya juga cenderung menghilangkan didict
mana-mana. Ya, konsistensi diri adalah nama tengah saya. ;)Bangun perintah dalam sebuah string dan gunakan
:exe
untuk menjalankannya. Lihat:help execute
untuk lebih jelasnya.Dalam hal ini,
execute
digunakan untuk membuat panggilan ke fungsi dan memasukkan hasilnya dalam register, elemen-elemen yang berbeda dari perintah harus digabungkan dengan.
operator sebagai string biasa. Baris 3 seharusnya menjadi:sumber