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:functionToExecute
jest 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:functionToExecute
jest 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:functionToExecute
jest 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 dict
tu 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-a
z 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 gvd
usuwać starego wyboru, normal "xp
zastą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 x
już prawidłowy typ (tj. Znakowy, liniowy lub blokowy).
dict
słowa kluczowego. Dotyczy to twoich „metod klasowych”. Zobaczyć:h numbered-function
.dict
z żadnejMyClass
funkcji). Uważam to jednak za mylące, dlatego staram siędict
wyraźnie dodawać .dict
do metod obiektowych, ale nie do metod klasowych, aby pomóc wyjaśnić swoje zamiary?self
jest różne dla metod klasowych i metod obiektowych - to sama klasa w pierwszym przypadku, a instancja bieżącego obiektu w drugim. Z tego powodu zawsze odnoszę się do samej klasy jako „g:MyClass
nigdy nie używam”self
, a przede wszystkim widzę wdict
niej przypomnienie, że można z niej korzystaćself
(tj. Funkcja, któradict
zawsze działa na instancję obiektu). Z drugiej strony nie używam metod klasowych, a kiedy to robię, mam tendencję do omijaniadict
wszystkiego. Tak, moja konsekwencja to moje drugie imię. ;)Zbuduj polecenie w ciągu i użyj go,
:exe
aby je uruchomić. Zobacz:help execute
po więcej szczegółów.W takim przypadku
execute
służy do wywołania funkcji i umieszczenia wyniku w rejestrze, różne elementy polecenia muszą zostać połączone z.
operatorem jako ciąg zwykły. Wiersz 3 powinien wtedy stać się:źródło