루아 레퍼런스 매뉴얼 — 언어: 가시성 규칙
루아 레퍼런스 매뉴얼 — 언어: 가시성 규칙 (Visibility Rules)
변수를 선언하고 나서 어디까지 그 변수가 보이는지, 언제 그 변수를 다시 만들 수 있는지에 대한 규칙을 정리해 볼게요. 루아는 어휘적(렉시컬) 스코프를 쓰는 언어라서, 변수가 보이는 범위가 코드의 구조, 그러니까 중괄호 블록이 아니라 do ~ end 같은 블록의 구조에 따라 정해져요. 이 규칙만 제대로 알면 지역 변수가 어디서 살아 있고 어디서부터 새로 태어나는지 헷갈리지 않게 됩니다.
출처: Lua 5.4 Reference Manual, §3.5 "Visibility Rules" (https://www.lua.org/manual/5.4/manual.html)
본문
루아는 어휘적 스코프(lexical scoping)를 사용하는 언어입니다. 지역 변수의 스코프(유효 범위)는 그 선언 뒤에 오는 첫 번째 문장부터, 그 선언을 포함하는 가장 안쪽 블록의 마지막 비-void 문장까지 이어집니다. 여기서 void 문장은 레이블(label)과 빈 문장(empty statement)을 말해요.
다음 예시를 볼게요.
x = 10 -- global variable
do -- new block
local x = x -- new 'x', with value 10
print(x) --> 10
x = x+1
do -- another block
local x = x+1 -- another 'x'
print(x) --> 12
end
print(x) --> 11
end
print(x) --> 10 (the global one)
여기서 한 가지 짚고 넘어갈 게 있어요. local x = x처럼 선언할 때, 방금 선언되는 새 x는 아직 스코프 안에 들어오지 않은 상태예요. 그래서 오른쪽의 두 번째 x는 바깥쪽에 있던 변수(위 예시에서는 전역 변수 10)를 가리킵니다. 새 변수가 자기 자신을 참조할 수는 없다는 뜻이죠.
어휘적 스코프 규칙 덕분에, 지역 변수는 그 스코프 안에서 정의된 함수들이 자유롭게 접근할 수 있습니다. 안쪽 함수가 사용하는 이런 지역 변수를 그 함수 안에서는 업밸류(upvalue) 라고 불러요. 줄여서 외부 지역 변수(external local variable), 혹은 그냥 외부 변수(external variable)라고도 합니다.
한 가지 더 기억할 점은, local 문장이 실행될 때마다 새로운 지역 변수를 만든다는 겁니다. 다음 예시를 봐요.
a = {}
local x = 20
for i = 1, 10 do
local y = 0
a[i] = function () y = y + 1; return x + y end
end
이 루프는 열 개의 클로저(closure)를 만들어요. 즉 익명 함수의 인스턴스가 열 개 생기는 거죠. 이 클로저들은 각각 서로 다른 y 변수를 사용하는 반면, 모두 같은 x 변수를 공유합니다. y는 루프를 돌 때마다 local y = 0으로 새로 만들어지고, x는 루프 바깥에서 한 번만 선언됐기 때문이에요.
더 알아보기
- 지역 변수의 선언과 할당, 그리고 스코프에 대한 이 규칙은 동일 매뉴얼의 §3.4 "Local Declarations", §3.3.7 "Local Declarations" 구간에서 더 자세히 다룹니다.
- 클로저와 업밸류의 실제 동작(공유되는 변수 vs. 각각 따로 생기는 변수)은 함수를 다루는 §2.5 "Function Definitions", §3.4.10 "Function Definitions"와 함께 보면 이해가 빨라져요.
- 함수가 자신이 정의된 스코프의 지역 변수를 계속 붙잡는 upvalue 개념은 공식 매뉴얼의 §2.6 "Visibility" 및 함수 API(§4.3 lua_upvalueindex)에서도 이어집니다.