코딩 · 프로그래밍 언어
초보자를 위한 Lua 기초 튜토리얼
핵심 답변
Lua는 게임, Roblox(Luau 방언 사용), Neovim, Redis, 임베디드 장치에서 쓰이는 가볍고 내장하기 쉬운 스크립트 언어입니다. 문법이 간결하고 자료구조가 테이블 하나뿐이며, 이 테이블이 배열, 딕셔너리, 객체 역할을 모두 합니다. 이 페이지에서는 Lua 설치, 변수와 자료형, 제어 흐름, 함수, 테이블, 메타테이블, pcall을 이용한 오류 처리와 완성된 예제를 설명합니다.
Lua란 무엇이며 어디에 쓰이는가
Lua는 1993년 브라질의 대학인 PUC-Rio에서 만든 작고 빠른 동적 타입 스크립트 언어입니다. 인터프리터 전체가 C로 작성된 작은 라이브러리여서 더 큰 프로그램 안에 쉽게 내장할 수 있습니다. 자료구조는 테이블 하나뿐이고 개념도 매우 적어서 빠르게 배울 수 있습니다.
Lua는 주로 내장형 스크립트 언어로 쓰입니다. 게임 엔진과 게임(Roblox는 Luau라는 Lua 방언을 쓰고, LÖVE와 Defold도 Lua를 씁니다), Neovim 편집기, Redis 데이터베이스, OpenResty를 올린 Nginx 같은 네트워크 도구, 수많은 임베디드 장치가 대표적입니다. LuaJIT은 Lua 5.1 코드를 위한 널리 쓰이는 JIT(just-in-time) 컴파일러입니다.
Lua 설치와 Hello, world 실행
패키지 관리자(예: brew install lua 또는 apt install lua5.4)로 Lua를 설치하거나 lua.org의 소스에서 직접 빌드합니다. lua만 입력하면 대화형 프롬프트가 열립니다.
-- hello.lua
print("Hello, world!")lua hello.lua
# Hello, world!주석은 --로 시작하고, 블록 주석은 --[[ ... ]]로 씁니다. 문장 끝에 세미콜론은 필요 없습니다.
변수와 기본 자료형
변수는 기본적으로 전역입니다. 정말 전역이 필요한 경우가 아니라면 항상 local로 선언하세요. Lua에는 기본 자료형이 여덟 가지 있으며, 매일 쓰는 것은 아래와 같습니다.
local name = "Lua"
local year = 1993 -- integer
local pi = 3.14159 -- float
local ok = true
local nothing = nil
print(type(name), type(year), type(nothing)) -- string number nil
print(math.type(year), math.type(pi)) -- integer float
print(name .. " " .. year) -- Lua 1993 (.. joins strings)
print(#name) -- 3 (length)
print(7 / 2, 7 // 2, 7 % 2, 2 ^ 10) -- 3.5 3 1 1024.0
print(string.format("%.2f", pi)) -- 3.14
print(tonumber("42") + 1, tostring(10)) -- 43 10| 자료형 | 예시 | 설명 |
|---|---|---|
| nil | nil | 값이 없음을 나타내며, 설정하지 않은 변수는 nil입니다 |
| boolean | true, false | false와 nil만 거짓으로 취급하며, 0과 ""는 참입니다 |
| number | 42, 3.14 | Lua 5.3부터 정수와 부동소수점 하위 자료형이 있습니다 |
| string | "hi", 'hi', [[long]] | 변경할 수 없는 바이트 문자열 |
| table | {1, 2, x = 3} | 유일한 자료구조 |
| function | function() end | 일급 값 |
같지 않음 연산자는 !=가 아니라 ~=입니다. 논리 연산자는 and, or, not이라는 단어를 씁니다.
제어 흐름
블록은 end 키워드로 끝납니다. Lua에는 if/elseif/else, while, repeat ... until, 숫자 for, 반복자와 함께 쓰는 일반 for가 있습니다.
local score = 72
if score >= 90 then
print("A")
elseif score >= 70 then
print("B") -- B
else
print("C")
end
for i = 1, 3 do -- 1 to 3, inclusive
io.write(i, " ") -- 1 2 3
end
print()
for i = 10, 1, -4 do io.write(i, " ") end -- 10 6 2
print()
local n = 3
while n > 0 do n = n - 1 end
repeat
n = n + 1
until n >= 2
print(n) -- 2continue 문은 없습니다. ::continue:: 레이블과 goto continue를 쓰거나 if로 반복문 구조를 바꾸세요.
함수
함수는 값입니다. ...로 가변 인자를 받을 수 있고 여러 값을 반환할 수 있습니다. 클로저는 바깥 스코프의 지역 변수를 캡처합니다.
local function add(a, b)
return a + b
end
local function minmax(t)
local lo, hi = math.huge, -math.huge
for _, v in ipairs(t) do
lo, hi = math.min(lo, v), math.max(hi, v)
end
return lo, hi -- two return values
end
local function counter()
local count = 0
return function() -- a closure
count = count + 1
return count
end
end
print(add(2, 3)) -- 5
local lo, hi = minmax({4, 9, 1})
print(lo, hi) -- 1 9
local next_id = counter()
print(next_id(), next_id()) -- 1 2
local function sum(...)
local total = 0
for _, v in ipairs({...}) do total = total + v end
return total
end
print(sum(1, 2, 3)) -- 6테이블: 배열, 딕셔너리, 객체
테이블은 nil을 제외한 모든 값으로 인덱싱할 수 있는 연관 배열입니다. 같은 구조가 배열, 딕셔너리, 집합, 모듈, 객체로 쓰입니다. 관례상 배열은 인덱스 1부터 시작합니다.
local fruits = {"apple", "banana"}
table.insert(fruits, "cherry")
print(#fruits, fruits[1]) -- 3 apple
for i, f in ipairs(fruits) do -- array part, in order
print(i, f)
end
local ages = {ann = 31, bo = 25}
ages["cy"] = 40
ages.bo = nil -- remove a key
for k, v in pairs(ages) do -- all keys, order not defined
print(k, v)
end
table.sort(fruits, function(a, b) return a > b end)
print(table.concat(fruits, ", ")) -- cherry, banana, apple메타테이블과 객체지향 Lua
메타테이블은 Lua의 대표 기능입니다. 테이블에 메타테이블을 붙이면 동작을 바꿀 수 있습니다. __index는 없는 키를 채워 주고(상속에 사용), __add, __eq, __tostring 같은 필드는 연산자를 오버로드합니다. 콜론 문법 obj:method()는 객체를 숨겨진 첫 번째 매개변수 self로 전달합니다.
local Vector = {}
Vector.__index = Vector
function Vector.new(x, y)
return setmetatable({x = x, y = y}, Vector)
end
function Vector:length()
return math.sqrt(self.x ^ 2 + self.y ^ 2)
end
Vector.__add = function(a, b) return Vector.new(a.x + b.x, a.y + b.y) end
Vector.__tostring = function(v) return "(" .. v.x .. ", " .. v.y .. ")" end
local v = Vector.new(3, 4) + Vector.new(0, 0)
print(tostring(v)) -- (3, 4)
print(v:length()) -- 5.0Lua에는 코루틴(coroutine.create, coroutine.resume, coroutine.yield)도 있어서 함수를 일시 정지했다가 나중에 재개할 수 있습니다. 게임 스크립트에서는 여러 프레임에 걸쳐 단계별로 진행되는 동작에 자주 사용합니다.
오류 처리
error(message)로 오류를 발생시키고, pcall(보호 호출)로 잡습니다. pcall은 프로그램을 멈추지 않고 false와 오류를 반환합니다. io.open처럼 많은 라이브러리 함수는 오류를 발생시키는 대신 nil과 오류 메시지를 반환합니다.
local function divide(a, b)
if b == 0 then
error("division by zero")
end
return a / b
end
local ok, result = pcall(divide, 10, 2)
print(ok, result) -- true 5.0
ok, result = pcall(divide, 1, 0)
print(ok, result) -- false script.lua:3: division by zero
local f, err = io.open("missing.txt", "r")
if not f then print("open failed: " .. err) end오류 메시지의 파일 이름과 줄 번호는 코드가 실행되는 위치에 따라 달라집니다. assert(value, message)는 value가 false 또는 nil이면 오류를 발생시키며, 결과를 확인하는 간단한 방법입니다.
작은 완성 프로그램: 단어 수 세기
이 프로그램은 패턴 매칭으로 텍스트의 단어를 세고, 빈도순으로 정렬해 상위 세 개를 출력합니다. 문자열 패턴, 테이블, 사용자 정의 비교 함수를 이용한 정렬, 문자열 포맷을 사용합니다.
local text = [[
The cat and the dog. The dog sat,
and the cat ran.
]]
local counts = {}
for word in text:lower():gmatch("%a+") do
counts[word] = (counts[word] or 0) + 1
end
local list = {}
for word, n in pairs(counts) do
list[#list + 1] = {word = word, n = n}
end
table.sort(list, function(a, b)
if a.n ~= b.n then return a.n > b.n end
return a.word < b.word
end)
for i = 1, 3 do
print(string.format("%-4s %d", list[i].word, list[i].n))
end
-- the 4
-- and 2
-- cat 2다음 단계
- lua.org의 Lua 레퍼런스 매뉴얼은 짧지만 빠짐없이 정리되어 있습니다.
- Lua 설계자 중 한 명인 Roberto Ierusalimschy의 Programming in Lua는 초판이 온라인에 무료로 공개되어 있습니다.
- Neovim의 Lua 가이드, LÖVE, Roblox의 Luau 문서처럼 사용하는 호스트 환경의 문서를 참고하세요.
- Lua 모듈용 패키지 관리자인 LuaRocks.
자주 묻는 질문
Lua 배열은 왜 1부터 시작하나요?
Lua 설계자들은 수학과 프로그래머가 아닌 사람들의 일반적인 관례에 맞추려고 1부터 시작하는 인덱싱을 택했습니다. ipairs, #, table.insert 같은 표준 라이브러리 함수는 모두 시퀀스가 1부터 시작한다고 가정합니다.
Lua가 Python보다 빠른가요?
표준 Lua 인터프리터는 작고 동적 언어치고 대체로 빠르며, LuaJIT은 많은 작업에서 훨씬 더 빠릅니다. 실제 속도는 작업에 따라 다르므로 직접 측정해 보세요.
pairs와 ipairs의 차이는 무엇인가요?
ipairs는 인덱스 1부터 첫 번째 nil이 나올 때까지 배열 부분을 순서대로 순회합니다. pairs는 테이블의 모든 키를 정해지지 않은 순서로 방문합니다.
Luau는 무엇인가요?
Luau는 Roblox가 Lua 5.1에서 파생해 개발한 언어입니다. 점진적 타입 지정과 성능 개선이 추가되었고 Roblox 게임에 쓰입니다.
Lua는 초보자에게 적합한가요?
네. 문법이 작고 일관되며 개념이 적어서 게임 모딩과 교육에 인기가 있습니다. 표준 라이브러리가 최소한이라 더 많은 기능은 호스트 프로그램이나 모듈에 의존해야 합니다.