Щоб відповісти на ваше запитання: прототип call()
в посібнику є call({func}, {arglist} [, {dict}])
; {arglist}
аргумент повинен бути буквально об'єкт списку, а НЕ список аргументів. Тобто ви повинні написати це так:
let @x = call(a:functionToExecute, [GetSelectedText()])
Це передбачає a:functionToExecute
або Funcref (див. :help Funcref
), Або ім'я функції (тобто рядок, наприклад 'Type1ProcessString'
).
Тепер це потужна функція, яка надає Vim свого роду якість LISP, але ви, мабуть, рідко використовуєте її як вище. Якщо a:functionToExecute
це рядок, ім'я функції, то ви можете це зробити:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
і ви б назвали обгортку з назвою функції:
call Wrapper('Type1ProcessString')
Якщо з іншого боку a:functionToExecute
є Funcref, ви можете зателефонувати йому безпосередньо:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
але вам потрібно викликати обгортку так:
call Wrapper(function('Type1ProcessString'))
Ви можете перевірити наявність функцій за допомогою exists('*name')
. Це робить можливим такий маленький трюк:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
тобто функція, яка використовує вбудований, strwidth()
якщо Vim достатньо новий, щоб мати його, і відкидається на strlen()
інше (я не стверджую, що таке резервне значення має сенс; я просто кажу, що це можна зробити). :)
За допомогою функцій словника (див. :help Dictionary-function
) Ви можете визначити щось, що нагадує класи:
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
Тоді ви створили б такі об'єкти:
let little_object = g:MyClass.New({'foo': 'bar'})
І назвіть його методи:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
Ви також можете мати атрибути та методи класу:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(зауважувати тут не потрібно dict
).
Редагувати: Підкласифікація - це приблизно так:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
Тонким моментом тут є використання copy()
замість deepcopy()
. Причиною цього є можливість отримати доступ до атрибутів батьківського класу за посиланням. Цього можна досягти, але це дуже неміцно, і правильно це - далеко не банальне значення. Ще одна потенційна проблема полягає в тому , що цей вид підкласу це ототожнення is-a
з has-a
. З цієї причини атрибути класу, як правило, не варті болю.
Гаразд, цього має бути достатньо, щоб дати вам трохи їжі для роздумів.
Назад до початкового фрагмента коду є дві деталі, які можна вдосконалити:
- вам не потрібно
normal gvd
буде видаляти старий вибір, normal "xp
він замінить його, навіть якщо ви його попередньо не вб'єте
- використовувати
call setreg('x', [lines], type)
замість let @x = [lines]
. Це явно встановлює тип регістра x
. В іншому випадку ви покладаєтесь на x
те, що ви вже маєте правильний тип (тобто символом, лінією чи блоком).
dict
ключове слово. Це стосується ваших "методів класу". Див:h numbered-function
.