tools/vim

Learn Vimscript The Hard Way - 24: Functions Arguments

seul chan 2020. 3. 31. 08:52

Functions Arguments

Vimscript의 함수도 당연히 인자를 받을 수 있다.

:function DisplayName(name)
:  echom "Hello!  My name is:"
:  echom a:name
:endfunction

이제 인자로 함수를 실행시켜보자.

:call DisplayName("Your Name")

vim은 Hello! My name is:Your Name 두 줄을 출력할 것이다.

이름 앞에 a:를 사용하였는데, 이는 앞 챕터 Variable Scoping에서 보았던 Function argument scoping이다. 이를 사용하지 않으면 에러가 나는 것을 볼 수 있다.

:function UnscopedDisplayName(name)
:  echom "Hello!  My name is:"
:  echom name
:endfunction
:call UnscopedDisplayName("Your Name")

이런 에러가 발생한다.

E121: Undefined variable: name

Vimscript 함수를 작성하여 인자를 받을 때에는 반드시 a: prefix를 사용해 주어야 한다.

Varags

Vimscript 함수에서는 JavaScript나 Python처럼 variable-length argument list를 받을 수 있다. (python의 args라고 생각하면 될듯하다)

:function Varg(...)
:  echom a:0
:  echom a:1
:  echo a:000
:endfunction

:call Varg("a", "b")

각각 2, a, ["a", "b"]를 출력하는데 각각을 살펴보자.

함수 정의시에 ...는 함수가 어떤 개수의 인자도 받을 수 있다고 명시해주는 역할을 한다. 파이썬의 *args와 비슷.

첫 번 째 줄의 a:02를 반환한다. a:0은 인자의 총 개수를 반환해준다. 위에서는 a, b 두 개를 넘겨주었으니 2를 반환한 것.

두 번 째 줄의 a:1a를 반환한다. 이는 첫 번 째 인자를 반환한 것. a:2b를 반환할 것이다.

세 번 째 줄은 조금 특이하다. 함수가 varargs를 가지면 a:000은 모든 extra arguments의 리스트를 반환한다. echom은 리스트에 사용이 안 되기 때문에 echo를 사용하였다.

list에 대해서는 이후 챕터에서 다룰 예정이니 몰라도 상관없다고 한다.

:function Varg2(foo, ...)
:  echom a:foo
:  echom a:0
:  echom a:1
:  echo a:000
:endfunction

:call Varg2("a", "b", "c")

위의 예시에서는 a를 named argument로 들어가서 a:foo에서 a가 반환되고, a:000에서는 나버지 b, c가 반환되는 것을 볼 수 있다.

Assignment

foo를 함수 안에서 정의하는 아래 예시를 실행해보자.

:function Assign(foo)
:  let a:foo = "Nope"
:  echom a:foo
:endfunction

:call Assign("test")

다음과 같은 에러가 발생하는데, 이는 인자를 재정의할 수 없기 때문이다.

E46: Cannot change read-only variable "a:foo"

이제 다음 예시를 실행해보자.

:function AssignGood(foo)
:  let foo_tmp = a:foo
:  let foo_tmp = "Yep"
:  echom foo_tmp
:endfunction

:call AssignGood("test")

이제 의도한 대로 Yep이 출력되는 것을 볼 수 있다.

Exercises

  • Read the first two paragraphs of :help function-argument.

읽기 귀찮은 사람들을 위해 복붙해놓는다.

An argument can be defined by giving its name.  In the function this can then
be used as "a:name" ("a:" for argument).

Up to 20 arguments can be given, separated by commas.  After the named
arguments an argument "..." can be specified, which means that more arguments
may optionally be following.  In the function the extra arguments can be used
as "a:1", "a:2", etc.  "a:0" is set to the number of extra arguments (which
can be 0).  "a:000" is set to a |List| that contains these arguments.  Note
that "a:1" is the same as "a:000[0]".

The a: scope and the variables in it cannot be changed, they are fixed.
However, if a composite type is used, such as |List| or |Dictionary| , you can
change their contents.  Thus you can pass a |List| to a function and have the
function add an item to it.  If you want to make sure the function cannot
change a |List| or |Dictionary| use |:lockvar|.
  • Read :help local-variables.

예시를 실행시켜보자

Inside a function local variables can be used. These will disappear when the
function returns. Global variables need to be accessed with "g:".

Example: >

:function Table(title, ...)
:  echohl Title
:  echo a:title
:  echohl None
:  echo a:0 . " items:"
:  for s in a:000
:    echon ' ' . s
:  endfor
:endfunction

This function can then be called with: >

call Table("Table", "line1", "line2")
call Table("Empty Table")

To return more than one value, return a |List|: >

:function Compute(n1, n2)
:  if a:n2 == 0
:    return ["fail", 0]
:  endif
:  return ["ok", a:n1 / a:n2]
:endfunction

This function can then be called with: >

:let [success, div] = Compute(102, 6)
:if success == "ok"
:  echo div
:endif