Vimscript 배우기 cho.books
제 7 장 · 원서 §23–27

함수와 데이터 타입

함수 정의와 호출, 인자와 가변 인자. 그리고 숫자와 문자열 — Vimscript의 강제 형변환이 당신을 무는 자리들. 타입을 늘 의식하세요.

function! call varargs Number / Float String

Section 01함수 정의와 호출

대부분의 프로그래밍 언어처럼 Vimscript에도 함수가 있습니다. 그러나 곧 Vimscript 특유의 별난 점과 마주칩니다.

:function meow()를 실행하면 — 함수 정의가 시작될 것 같지만, 오류가 납니다. 스코프가 없는 Vimscript 함수는 대문자로 시작해야 합니다. 제대로 정의해 봅시다:

vimscript — 함수 정의
:function! Meow()
:  echom "Meow!"
:endfunction

:function! GetMeow()
:  return "Meow String!"
:endfunction

함수를 호출하는 방법은 두 가지입니다. 직접 호출할 때는 call 명령을 씁니다. 표현식 안에서 쓸 때는 그냥 함수 이름을 씁니다:

vimscript — 두 가지 호출 방법
:call Meow()           " 직접 호출 — 반환값은 버려짐
:echom GetMeow()       " 표현식 — 반환값을 echom에 전달
함정 function!의 느낌표는 "이미 같은 이름의 함수가 있으면 덮어쓰라"는 뜻입니다. 느낌표 없이 function만 쓰면, 같은 함수를 다시 정의할 때 오류가 납니다. vimrc를 소싱할 때마다 함수가 다시 정의되므로, 거의 항상 function!을 쓰세요.

Section 02암시적 반환

:echom Meow()를 실행하면 두 줄이 출력됩니다 — Meow!0. 첫 줄은 함수 안의 echom에서, 둘째 줄은 Vimscript 함수가 값을 반환하지 않으면 암시적으로 0을 반환한다는 사실에서 옵니다. 이것을 유리하게 쓸 수 있습니다:

vimscript — 암시적 0 반환을 활용
:function! TextwidthIsTooWide()
:  if &l:textwidth ># 80
:    return 1
:  endif
:endfunction

이 함수는 textwidth가 80보다 크면 1(참)을, 그렇지 않으면 — return 없이 끝나므로 — 암시적으로 0(거짓)을 반환합니다. 이 함수는 이전 장의 여러 개념을 한데 모읍니다: if 문, 옵션을 변수로, 옵션 변수의 로컬화(&l:), 대소문자 구분 비교(>#).

Section 03함수 인자와 가변 인자

함수가 받는 인자는 a: 스코프로 접근합니다:

vimscript — 함수 인자
:function! DisplayName(name)
:  echom "Hello! My name is:"
:  echom a:name          " 반드시 a: 접두사로 접근
:endfunction
함정 함수 인자는 반드시 a: 접두사로 접근해야 합니다 — echom name은 오류입니다. 또한 인자 변수는 재할당할 수 없습니다. 값을 바꾸려면 let tmp = a:foo처럼 로컬 변수에 복사하세요.

Vimscript 함수는 JavaScript나 Python처럼 가변 길이 인자를 받을 수 있습니다. 정의에 ...을 씁니다:

vimscript — 가변 인자 (varargs)
:function! Varg(...)
:  echom a:0      " 추가 인자의 개수
:  echom a:1      " 첫 번째 추가 인자
:  echo  a:000    " 모든 추가 인자의 리스트
:endfunction
:call Varg("a", "b")

...은 Python의 *args와 같습니다. a:0은 추가 인자의 개수, a:1·a:2는 각 추가 인자, a:000은 모든 추가 인자의 리스트입니다. 일반 인자와 함께 쓸 수도 있습니다.

Section 04숫자 — Number와 Float

Vimscript에는 두 가지 숫자 타입이 있습니다 — Number(32비트 부호 있는 정수)와 Float(부동소수점). Number는 여러 표기법으로 쓸 수 있습니다:

vimscript — 숫자 표기
:echom 100        " 100
:echom 0xff       " 255 — 16진수
:echom 017        " 15 — 8진수 (0으로 시작)
:echo 5.45e+3    " 5450.0 — Float 지수 표기
함정 0190으로 시작하지만 유효한 8진수가 아니므로 Vim이 조용히 10진수로 취급합니다. 8진수는 헷갈리기 쉬우니 가능하면 피하세요. Float는 소수점과 그 뒤의 숫자가 필수입니다 — 5e10은 충돌하고, 5.0e10이라야 합니다.

강제 형변환: Number와 Float를 함께 연산하면 Number가 Float로 변환됩니다 — 2 * 2.04.0. 나눗셈: 두 Number를 나누면 나머지가 버려집니다 — 3 / 21. 부동소수점 나눗셈을 원하면 한쪽이 Float여야 합니다 — 3 / 2.01.5.

Section 05문자열과 그 함정

Vim은 텍스트를 다루는 도구이므로 String을 자주 쓰게 됩니다. 문자열을 더하려고 하면 — 함정에 빠집니다:

vimscript — + 가 아니라 . 로 잇는다
:echom "Hello, " + "world"   " 0 — + 는 숫자 연산자!
:echom "Hello, " . "world"   " Hello, world — . 가 연결 연산자
함정 +는 Number 전용입니다. 문자열을 +로 더하면 Vim이 숫자로 강제 변환해 버립니다. 문자열을 잇는 연산자는 점(.)입니다. 게다가 +는 문자열을 Float로는 변환하지 않습니다 — 10 + "10.10"20입니다(소수점 이하가 버려짐).
개념 일반 문자열과 리터럴 문자열

큰따옴표 문자열은 \n(개행), \"(따옴표), \\(백슬래시) 같은 이스케이프 시퀀스를 해석합니다.

작은따옴표 리터럴 문자열은 문자를 있는 그대로 둡니다 — '\n\\'는 문자 그대로 \n\\입니다. 유일한 예외는 작은따옴표 두 개가 따옴표 하나가 된다는 것뿐입니다.

이 이야기의 교훈 Vim은 JavaScript와 비슷합니다 — 타입을 느슨하게 다루게 해주지만, 그러면 언젠가 당신을 뭅니다. Vimscript를 쓸 때는 각 변수의 타입을 항상 알고 있으세요. 타입을 바꿔야 하면, 당장은 꼭 필요하지 않더라도 함수로 명시적으로 바꾸세요. Vim의 강제 변환에 의존하지 마세요.
모션 · 문자열을 + 로 더하면 01 / 4
스페이스: 재생 · ← →: 단계 이동

Section 06연습문제

  • :help :call을 읽으세요(지금은 "range"는 무시). 함수에 인자를 몇 개까지 전달할 수 있나요?
  • :help E124의 첫 단락을 읽고, 함수 이름에 쓸 수 있는 문자를 알아내세요.
  • :help return, :help function-argument, :help local-variables를 읽으세요.
  • :help Float:help floating-point-precision을 읽으세요.
  • :help expr-quote를 읽고, 일반 문자열에서 쓸 수 있는 이스케이프 시퀀스를 검토하세요. 탭 문자를 넣는 법을 알아내세요.
  • :help literal-string을 읽으세요.