Aby odpowiedzieć na twoje pytanie: prototyp call()w instrukcji jest call({func}, {arglist} [, {dict}]); {arglist}argumentem musi być dosłownie obiekt List, a nie lista argumentów. Oznacza to, że musisz to napisać w ten sposób:
let @x = call(a:functionToExecute, [GetSelectedText()])
Zakłada się, że a:functionToExecutejest to Funcref (patrz :help Funcref) lub nazwa funkcji (tj. Ciąg znaków, taki jak 'Type1ProcessString').
To potężna funkcja, która daje Vimowi jakość przypominającą LISP, ale prawdopodobnie rzadko używałbyś go jak wyżej. Jeśli a:functionToExecutejest ciągiem, nazwą funkcji, możesz to zrobić:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
i wywołałbyś opakowanie z nazwą funkcji:
call Wrapper('Type1ProcessString')
Jeśli z drugiej strony a:functionToExecutejest Funcref, możesz wywołać go bezpośrednio:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
ale musisz wywołać opakowanie w ten sposób:
call Wrapper(function('Type1ProcessString'))
Możesz sprawdzić istnienie funkcji za pomocą exists('*name'). Umożliwia to następującą małą sztuczkę:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
tj. funkcja, która korzysta z wbudowanego, strwidth()jeśli Vim jest wystarczająco nowy, aby go mieć, i wraca do strlen()innych (nie twierdzę, że taka awaria ma sens; mówię tylko, że można to zrobić). :)
Za pomocą funkcji słownika (patrz :help Dictionary-function) możesz zdefiniować coś przypominającego klasy:
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
Następnie utworzyłbyś takie obiekty:
let little_object = g:MyClass.New({'foo': 'bar'})
I nazwij jej metody:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
Możesz także mieć atrybuty i metody klas:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(zauważ, że nie ma dicttu potrzeby ).
Edycja: Podklasowanie jest mniej więcej takie:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
Subtelnym punktem tutaj jest użycie copy()zamiast deepcopy(). Powodem tego jest dostęp do atrybutów klasy nadrzędnej przez odniesienie. Można to osiągnąć, ale jest to bardzo kruche, a poprawne wykonanie go wcale nie jest trywialne. Innym potencjalnym problemem jest to, że tego rodzaju zrównują podklasy is-az has-a. Z tego powodu atrybuty klasy zwykle nie są tak naprawdę warte bólu.
Ok, to powinno wystarczyć, aby dać ci trochę do myślenia.
Wracając do początkowego fragmentu kodu, można go ulepszyć w dwóch szczegółach:
- nie musisz
normal gvdusuwać starego wyboru, normal "xpzastąpi go, nawet jeśli nie zabijesz go jako pierwszy
- użyj
call setreg('x', [lines], type)zamiast let @x = [lines]. To wyraźnie określa typ rejestru x. W przeciwnym razie polegasz na tym, że masz xjuż prawidłowy typ (tj. Znakowy, liniowy lub blokowy).
dictsłowa kluczowego. Dotyczy to twoich „metod klasowych”. Zobaczyć:h numbered-function.