귀하의 질문에 대답하기 위해 : 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
.