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에서는 nilfalse만 거짓으로 취급, 나머지는 참)

  • 문자열 연결: ..

 
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

에러 처리 (pcallxpcall)

pcall (protected call)은 함수를 안전 모드에서 실행하여, 실행 중 오류가 발생해도 프로그램이 중단되지 않고 오류를 잡아낼 수 있게 합니다.

xpcallpcall과 유사하지만, 오류 발생 시 호출될 오류 처리 함수를 지정할 수 있습니다.

 
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가 임베디드 스크립팅 언어로서 강력한 이유 중 하나입니다.

더 읽어보기: https://www.lua.org/manual/5.4/manual.html#4