เพื่อตอบคำถามของคุณ: ต้นแบบของ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
ที่นี่)
แก้ไข: Subclassing มีลักษณะดังนี้:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
จุดที่ลึกซึ้งที่นี่คือการใช้แทนcopy()
deepcopy()
สาเหตุของการทำเช่นนี้คือสามารถเข้าถึงคุณลักษณะของคลาสพาเรนต์โดยอ้างอิง สิ่งนี้สามารถบรรลุผลได้ แต่มันมีความเปราะบางอย่างยิ่งและทำให้ถูกต้องอยู่ไกลจากเรื่องเล็กน้อย อีกปัญหาที่อาจเกิดขึ้นคือว่าชนิดของ conflates subclass นี้ด้วยis-a
has-a
ด้วยเหตุนี้คุณสมบัติของชั้นเรียนจึงไม่คุ้มกับความเจ็บปวด
ตกลงนี่น่าจะเพียงพอแล้วที่จะให้อาหารแก่คุณ
กลับไปที่ข้อมูลโค้ดเริ่มต้นของคุณมีสองรายละเอียดซึ่งสามารถปรับปรุงได้:
- คุณไม่จำเป็นต้อง
normal gvd
ลบสิ่งที่เลือกเก่าออกnormal "xp
จะแทนที่มันแม้ว่าคุณจะไม่ได้ฆ่ามันเสียก่อน
- ใช้แทน
call setreg('x', [lines], type)
let @x = [lines]
นี่เป็นการกำหนดประเภทของการลงทะเบียนx
อย่างชัดเจน มิฉะนั้นคุณจะต้องพึ่งพาx
ประเภทที่ถูกต้องอยู่แล้ว (เช่น characterwise, linewise หรือ blockwise)
dict
คำหลัก สิ่งนี้ใช้กับ "วิธีการเรียน" ของคุณ:h numbered-function
ดู