Để trả lời câu hỏi của bạn: nguyên mẫu call()
trong hướng dẫn là call({func}, {arglist} [, {dict}])
; các {arglist}
tham số cần phải được theo nghĩa đen một đối tượng List, không phải là một danh sách các đối số. Đó là, bạn phải viết nó như thế này:
let @x = call(a:functionToExecute, [GetSelectedText()])
Giả định a:functionToExecute
này là Funcref (xem :help Funcref
) hoặc tên của hàm (tức là một chuỗi, chẳng hạn như 'Type1ProcessString'
).
Bây giờ, đó là một tính năng mạnh mẽ mang lại cho Vim một loại chất lượng giống như LISP, nhưng có lẽ bạn hiếm khi sử dụng nó như trên. Nếu a:functionToExecute
là một chuỗi, tên của một hàm, thì bạn có thể làm điều này:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
và bạn sẽ gọi trình bao bọc với tên của hàm:
call Wrapper('Type1ProcessString')
Nếu mặt khác a:functionToExecute
là Funcref, bạn có thể gọi trực tiếp:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
nhưng bạn cần gọi trình bao bọc như thế này:
call Wrapper(function('Type1ProcessString'))
Bạn có thể kiểm tra sự tồn tại của các chức năng với exists('*name')
. Điều này có thể thực hiện các mẹo nhỏ sau đây:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
tức là một hàm sử dụng tích hợp strwidth()
nếu Vim đủ mới để có nó và quay trở lại strlen()
nếu không (tôi không cho rằng một dự phòng như vậy có ý nghĩa; tôi chỉ nói rằng nó có thể được thực hiện). :)
Với các hàm từ điển (xem :help Dictionary-function
), bạn có thể định nghĩa một cái gì đó tương tự như các lớp:
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
Sau đó, bạn sẽ khởi tạo các đối tượng như thế này:
let little_object = g:MyClass.New({'foo': 'bar'})
Và gọi các phương thức của nó:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
Bạn cũng có thể có các thuộc tính và phương thức lớp:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(thông báo không cần dict
ở đây).
Chỉnh sửa: Phân lớp là một cái gì đó như thế này:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
Điểm tinh tế ở đây là việc sử dụng copy()
thay vì deepcopy()
. Lý do cho điều này là để có thể truy cập các thuộc tính của lớp cha bằng cách tham chiếu. Điều này có thể đạt được, nhưng nó rất mong manh và làm cho nó trở nên xa vời. Một vấn đề tiềm năng khác là loại lớp con này liên kết is-a
với has-a
. Vì lý do này, các thuộc tính lớp thường không thực sự đáng giá.
Ok, điều này là đủ để cung cấp cho bạn một số thực phẩm cho suy nghĩ.
Quay lại đoạn mã ban đầu của bạn, có hai chi tiết có thể được cải thiện:
- bạn không cần
normal gvd
xóa lựa chọn cũ, normal "xp
sẽ thay thế ngay cả khi bạn không giết nó trước
- sử dụng
call setreg('x', [lines], type)
thay vì let @x = [lines]
. Điều này đặt rõ ràng các loại của thanh ghi x
. x
Mặt khác, bạn đang dựa vào việc đã có loại chính xác (nghĩa là theo chiều dọc, theo chiều dọc hoặc theo chiều dọc).
dict
từ khóa. Điều này áp dụng cho "phương thức lớp" của bạn. Xem:h numbered-function
.