Lua 내용 정리
알고 있는 중요한 내용 정리
Lua는 가볍고 확장 가능한 스크립트 언어로, 주로 임베디드 시스템이나 게임 개발에 많이 사용됩니다. C 언어와의 통합이 용이하며, 배우기 쉬운 문법을 가지고 있습니다.
Lua
Lua는 동적 타입 언어이며, 절차적 프로그래밍, 객체 지향 프로그래밍, 함수형 프로그래밍, 데이터 기술 프로그래밍 등 다양한 프로그래밍 패러다임을 지원합니다. 주요 특징은 다음과 같습니다:
-
가벼움: Lua 인터프리터는 매우 작고 빠릅니다.
-
이식성: ANSI C로 작성되어 다양한 플랫폼에서 실행 가능합니다.
-
확장성: C/C++ 코드를 Lua에서 호출하거나, Lua 코드를 C/C++ 애플리케이션에 통합하기 쉽습니다.
-
단순함: 문법이 간결하고 배우기 쉽습니다.
-
동적 타입: 변수의 타입은 런타임에 결정됩니다.
-
테이블: Lua의 유일한 데이터 구조화 메커니즘으로, 배열, 해시맵, 객체 등 다양한 형태로 사용될 수 있습니다.
더 읽어보기: Lua 공식 웹사이트
기본 문법
주석
-- 한 줄 주석
--[[
여러 줄 주석
입니다.
--]]
변수
Lua의 변수는 기본적으로 전역 변수입니다. 지역 변수를 사용하려면 local
키워드를 사용해야 합니다.
-- 전역 변수
globalVar = 10
-- 지역 변수
local localVar = "Hello, Lua!"
print(globalVar)
print(localVar)
데이터 타입
Lua는 다음과 같은 기본 데이터 타입을 가지고 있습니다:
-
nil
: 값이 없음을 나타냅니다. 할당되지 않은 변수의 기본값입니다. -
boolean
:true
또는false
값을 가집니다. -
number
: 부동소수점 숫자를 나타냅니다. (Lua 5.3부터 정수형도 지원) -
string
: 문자열을 나타냅니다. 작은따옴표('
) 또는 큰따옴표("
)로 감쌉니다. -
function
: 함수를 나타냅니다. -
userdata
: C 데이터를 Lua 변수에 저장할 수 있게 합니다. -
thread
: 코루틴을 나타냅니다. -
table
: Lua의 유일한 복합 데이터 타입입니다.
local a = nil
local b = true
local c = 10.5
local d = "Lua"
local e = function() print("function") end
local f = {} -- 빈 테이블
print(type(a)) -- nil
print(type(b)) -- boolean
print(type(c)) -- number
print(type(d)) -- string
print(type(e)) -- function
print(type(f)) -- table
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#2.1
연산자
-
산술 연산자:
+
,-
,*
,/
,//
(floor division, Lua 5.3+),%
,^
(지수) -
관계 연산자:
==
,~=
(같지 않음),<
,>
,<=
,>=
-
논리 연산자:
and
,or
,not
(Lua에서는nil
과false
만 거짓으로 취급, 나머지는 참) -
문자열 연결:
..
local x = 10
local y = 4
print(x + y) -- 14
print(x / y) -- 2.5
print(x // y) -- 2 (Lua 5.3+)
print("Hello" .. " " .. "World") -- Hello World
local condition1 = true
local condition2 = false
print(condition1 and condition2) -- false
print(condition1 or condition2) -- true
print(not condition1) -- false
제어 구조
조건문 (if-then-else)
local score = 85
if score >= 90 then
print("A")
elseif score >= 80 then
print("B")
elseif score >= 70 then
print("C")
else
print("F")
end
반복문 (while, repeat-until, for)
-- while 루프
local i = 1
while i <= 5 do
print("while: " .. i)
i = i + 1
end
-- repeat-until 루프 (조건이 참이 될 때까지 반복)
local j = 1
repeat
print("repeat: " .. j)
j = j + 1
until j > 5
-- 숫자형 for 루프
for k = 1, 5 do -- 1부터 5까지 1씩 증가 (기본 증가값은 1)
print("numeric for: " .. k)
end
for k = 5, 1, -1 do -- 5부터 1까지 1씩 감소
print("numeric for (reverse): " .. k)
end
-- 제네릭 for 루프 (주로 테이블 순회에 사용)
local myTable = {apple = 1, banana = 2, orange = 3}
for key, value in pairs(myTable) do
print("generic for (pairs): " .. key .. " = " .. value)
end
local myArray = {"a", "b", "c"}
for index, value in ipairs(myArray) do -- ipairs는 정수 인덱스 순서대로 순회
print("generic for (ipairs): " .. index .. " = " .. value)
end
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#3.3
함수
함수는 일급 값(first-class value)으로, 변수에 할당하거나 다른 함수의 인자로 전달하거나 반환 값으로 사용할 수 있습니다.
-- 함수 정의
function add(a, b)
return a + b
end
local result = add(3, 5)
print(result) -- 8
-- 익명 함수
local multiply = function(a, b)
return a * b
end
print(multiply(3, 5)) -- 15
-- 가변 인자 함수
function sum(...)
local total = 0
for _, v in ipairs({...}) do -- ...은 가변 인자를 테이블로 만듦
total = total + v
end
return total
end
print(sum(1, 2, 3, 4, 5)) -- 15
-- 다중 반환 값
function getCoordinates()
return 10, 20
end
local x, y = getCoordinates()
print(x, y) -- 10 20
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#3.4
테이블 (Tables)
테이블은 Lua의 유일한 데이터 구조화 메커니즘입니다. 배열, 딕셔너리(해시맵), 객체 등으로 사용될 수 있습니다.
-- 빈 테이블 생성
local t1 = {}
-- 배열 스타일
local arr = {10, 20, 30, "hello"}
print(arr[1]) -- 10 (Lua 배열 인덱스는 1부터 시작)
print(arr[4]) -- hello
arr[5] = 40
print(#arr) -- 5 (배열 길이 연산자 #)
-- 딕셔너리 스타일 (키-값 쌍)
local dict = {
name = "Lua",
version = 5.4,
["is good"] = true -- 키에 공백이나 특수문자가 있으면 대괄호와 따옴표 사용
}
print(dict.name) -- Lua
print(dict["version"]) -- 5.4
print(dict["is good"]) -- true
dict.year = 2020
print(dict.year) -- 2020
-- 테이블 순회
for k, v in pairs(dict) do
print(k .. ": " .. v)
end
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#2.5.7
메타테이블과 메타메소드 (Metatables and Metamethods)
메타테이블을 사용하여 테이블의 동작을 변경할 수 있습니다. 예를 들어, 두 테이블을 더하는 연산(+
)을 정의할 수 있습니다.
메타테이블은 일반 테이블이며, 특정 이벤트(예: __add
는 덧셈)에 대한 메타메소드를 가집니다.
local myTable1 = {10, 20}
local myTable2 = {30, 40}
local myMetatable = {
__add = function(t1, t2)
local resultTable = {}
for i = 1, math.max(#t1, #t2) do
resultTable[i] = (t1[i] or 0) + (t2[i] or 0)
end
return resultTable
end,
__tostring = function(t)
local s = "{"
for i, v in ipairs(t) do
s = s .. v .. (i == #t and "" or ", ")
end
return s .. "}"
end
}
setmetatable(myTable1, myMetatable)
-- myTable2는 myTable1과 같은 메타테이블을 공유하거나 자신만의 메타테이블을 가질 수 있습니다.
-- 여기서는 myTable1의 메타테이블이 __add 연산 시 사용됩니다.
local sumTable = myTable1 + myTable2 -- __add 메타메소드 호출
print(sumTable) -- {40, 60} (myMetatable의 __tostring 덕분에 이렇게 출력됨)
-- __index 메타메소드: 테이블에 없는 키에 접근할 때 호출
local defaults = { x = 0, y = 0 }
local point = { x = 10 }
setmetatable(point, { __index = defaults })
print(point.x) -- 10 (point 테이블에 존재)
print(point.y) -- 0 (point 테이블에 없으므로 defaults 테이블에서 찾음)
print(point.z) -- nil (defaults 테이블에도 없음)
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#2.4
모듈과 require
Lua는 require
함수를 사용하여 모듈을 로드합니다. 모듈은 일반적으로 테이블을 반환합니다.
-- mymodule.lua 파일 내용
local M = {}
function M.sayHello(name)
return "Hello, " .. name .. "!"
end
return M
-- 메인 파일에서 모듈 사용
local myModule = require("mymodule") -- 파일 확장자 .lua는 생략
print(myModule.sayHello("Lua User")) -- Hello, Lua User!
require
는 모듈을 한 번만 로드하고 그 결과를 캐시합니다.
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#pdf-require
코루틴 (Coroutines)
코루틴은 협력적 멀티태스킹을 위한 기능입니다. 여러 실행 흐름을 가질 수 있으며, coroutine.yield()
를 통해 실행을 중단하고, coroutine.resume()
을 통해 재개할 수 있습니다.
local co = coroutine.create(function(a, b)
print("co-body", a, b)
local r1 = coroutine.yield(a + b)
print("co-body", r1)
local r2 = coroutine.yield(a - b)
print("co-body", r2)
return "finished"
end)
print("main", coroutine.status(co)) -- main suspended
local status, res = coroutine.resume(co, 10, 20) -- 첫 번째 resume, 인자 전달
print("main", status, res) -- main true 30
status, res = coroutine.resume(co, "hello") -- yield에 값 전달
print("main", status, res) -- main true -10
status, res = coroutine.resume(co, "world")
print("main", status, res) -- main true finished
status, res = coroutine.resume(co) -- 이미 종료된 코루틴 재개 시도
print("main", status, res) -- main false cannot resume dead coroutine
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#2.6
에러 처리 (pcall
과 xpcall
)
pcall
(protected call)은 함수를 안전 모드에서 실행하여, 실행 중 오류가 발생해도 프로그램이 중단되지 않고 오류를 잡아낼 수 있게 합니다.
xpcall
은 pcall
과 유사하지만, 오류 발생 시 호출될 오류 처리 함수를 지정할 수 있습니다.
function mightFail(arg)
if type(arg) ~= "number" then
error("Expected a number, got " .. type(arg), 2) -- 2는 에러 메시지에 보고될 스택 레벨
end
return arg * 2
end
-- pcall 사용
local status, resultOrError = pcall(mightFail, 10)
if status then
print("Success:", resultOrError) -- Success: 20
else
print("Error:", resultOrError)
end
status, resultOrError = pcall(mightFail, "text")
if status then
print("Success:", resultOrError)
else
print("Error:", resultOrError) -- Error: [string "--[간단한 Lua 스크립트]..."]:2: Expected a number, got string
end
-- xpcall 사용
local function errorHandler(err)
print("Custom error handler:", err)
return "Error handled gracefully" -- xpcall의 반환값이 됨
end
status, resultOrError = xpcall(mightFail, errorHandler, "another text")
if status then
print("xpcall Success:", resultOrError)
else
print("xpcall Handled Error:", resultOrError) -- xpcall Handled Error: Error handled gracefully
end
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#pdf-pcall, https://www.lua.org/manual/5.4/manual.html#pdf-xpcall
가비지 컬렉션 (Garbage Collection)
Lua는 자동 메모리 관리를 위해 증분형 마크 앤 스윕(incremental mark-and-sweep) 가비지 컬렉터를 사용합니다. 개발자가 직접 메모리를 할당하거나 해제할 필요는 거의 없습니다.
collectgarbage()
함수를 통해 가비지 컬렉터를 제어할 수 있지만, 일반적으로는 필요하지 않습니다.
더 읽어보기: https://www.lua.org/manual/5.4/manual.html#2.5
Lua C API
Lua는 C/C++와 쉽게 통합될 수 있도록 강력한 C API를 제공합니다. 이를 통해 다음이 가능합니다:
-
C 함수를 Lua에서 호출 가능하게 만들기
-
Lua 코드를 C/C++ 애플리케이션에서 실행하고 제어하기
-
Lua의 기능을 C/C++로 확장하기
이는 Lua가 임베디드 스크립팅 언어로서 강력한 이유 중 하나입니다.