Um Ihre Frage zu beantworten: Der Prototyp call()
im Handbuch ist call({func}, {arglist} [, {dict}])
; Das {arglist}
Argument muss buchstäblich ein List-Objekt sein, keine Liste von Argumenten. Das heißt, Sie müssen es so schreiben:
let @x = call(a:functionToExecute, [GetSelectedText()])
Dies setzt a:functionToExecute
entweder eine Funcref (siehe :help Funcref
) oder den Namen einer Funktion (dh eine Zeichenfolge wie z. B. 'Type1ProcessString'
) voraus .
Das ist eine leistungsstarke Funktion, die Vim eine Art LISP-ähnliche Qualität verleiht, aber Sie würden sie wahrscheinlich selten wie oben verwenden. Wenn a:functionToExecute
es sich um eine Zeichenfolge handelt, den Namen einer Funktion, können Sie Folgendes tun:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
und Sie würden den Wrapper mit dem Namen der Funktion aufrufen:
call Wrapper('Type1ProcessString')
Wenn es sich dagegen a:functionToExecute
um einen Funcref handelt, können Sie ihn direkt aufrufen:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
Sie müssen den Wrapper jedoch folgendermaßen aufrufen:
call Wrapper(function('Type1ProcessString'))
Mit können Sie das Vorhandensein von Funktionen überprüfen exists('*name')
. Dies ermöglicht den folgenden kleinen Trick:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
dh eine Funktion, die die integrierte Funktion verwendet, strwidth()
wenn Vim neu genug ist, um sie zu haben, und auf etwas strlen()
anderes zurückgreift (ich behaupte nicht, dass ein solcher Fallback sinnvoll ist; ich sage nur, dass dies möglich ist). :) :)
Mit Wörterbuchfunktionen (siehe :help Dictionary-function
) können Sie etwas definieren, das Klassen ähnelt:
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
Dann würden Sie Objekte wie folgt instanziieren:
let little_object = g:MyClass.New({'foo': 'bar'})
Und nennen Sie seine Methoden:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
Sie können auch Klassenattribute und -methoden verwenden:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(Beachten Sie hier keine Notwendigkeit dict
).
Bearbeiten: Unterklassen sind ungefähr so:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
Der subtile Punkt hier ist die Verwendung von copy()
statt deepcopy()
. Der Grund dafür ist, auf die Attribute der übergeordneten Klasse als Referenz zugreifen zu können. Dies kann erreicht werden, ist aber sehr fragil und es ist alles andere als trivial, es richtig zu machen. Ein weiteres mögliches Problem ist , dass diese Art der Unterklasse verschmilzt is-a
mit has-a
. Aus diesem Grund sind Klassenattribute den Schmerz normalerweise nicht wirklich wert.
Ok, das sollte ausreichen, um zum Nachdenken anzuregen.
Zurück zu Ihrem ursprünglichen Code-Snippet gibt es zwei Details, die verbessert werden könnten:
- Sie müssen
normal gvd
die alte Auswahl nicht entfernen normal "xp
, sondern ersetzen sie, auch wenn Sie sie nicht zuerst beenden
- verwenden
call setreg('x', [lines], type)
statt let @x = [lines]
. Dies legt den Typ des Registers explizit fest x
. Andernfalls verlassen Sie sich darauf, x
dass Sie bereits den richtigen Typ haben (dh zeichenweise, zeilenweise oder blockweise).
dict
Schlüsselwort nicht. Dies gilt für Ihre "Klassenmethoden". Siehe:h numbered-function
.dict
derMyClass
Funktionen erforderlich ). Aber ich finde das verwirrend, deshalb neige ich dazu,dict
explizit hinzuzufügen .dict
Objektmethoden hinzu, aber nicht Klassenmethoden, um Ihre Absicht zu verdeutlichen?self
für Klassenmethoden und für Objektmethoden unterschiedlich ist - im ersten Fall ist es die Klasse selbst und im zweiten Fall die Instanz des aktuellen Objekts. Aus diesem Grund bezeichne ich die Klasse selbst immer als "g:MyClass
nie verwendend"self
und sehe sie meistensdict
als Erinnerung daran, dass die Verwendung in Ordnung istself
( dh eine Funktion, diedict
immer auf eine Objektinstanz gewirkt hat). Dann benutze ich nicht viel Klassenmethoden, und wenn ich das tue, neige ich auch dazu,dict
überall wegzulassen . Ja, Selbstkonsistenz ist mein zweiter Vorname. ;)Erstellen Sie den Befehl in einer Zeichenfolge und verwenden Sie ihn
:exe
, um ihn auszuführen. Siehe:help execute
für weitere Details.In diesem Fall,
execute
um die Funktion aufzurufen und das Ergebnis in das Register zu schreiben, müssen die verschiedenen Elemente des Befehls.
als reguläre Zeichenfolge mit dem Operator verknüpft werden. Die Zeile 3 sollte dann werden:quelle