주석
function foo()
-- 한 줄 주석
--[[
구간(block) 주석
--]]
end
REMARK. 구간 주석 끝을 나타내는 '--]]'는 사실 ']]'만 쓰면 되지만 가독성면이나 편의성면에서 관용적으로 '--]]' 로 사용한다.
변수
루아에서는 기본적으로 모든 변수가 전역 변수 처리된다. 특정 스코프(scope)에서만 유효한 변수는 선언 앞에 local 한정자를 추가한다.
function foo()
a = 10 -- foo라는 함수 안에서 선언 되었지만 전역 변수
local b = 10 -- 지역 변수. foo 함수 내에서만 유효하다.
end
함수
기본 문법은 아래와 같다. function 키워드로 함수임을 선언하고 end로 함수의 끝을 나타낸다.
function 함수명([인자1,]...)
...
end
루아 함수는 한번에 여러 개의 리턴 값을 가질 수 있다.
function sum(x, y)
local ret = x + y
return x, y, ret
end
x, y, ret = sum(10, 10)
print(x, y, ret)
테이블
테이블은 루아(Lua)의 특별한 자료 구조다. 배열, 세트, 딕셔너리 등 다양한 자료 구조를 테이블이라는 하나의 자료 구조로 표현한다.
배열로써 테이블
-- 배열 스타일
a = {} -- 테이블 선언
a[1] = "a"
a[2] = "b"
a[3] = "c"
for i = 1, 3 do
print(a[i])
end
딕셔너리로써 테이블
user = {}
user["name"] = "Jason"
user["age"] = 10
user["job"] = "officer"
print(user["name"])
print(user["age"])
print(user["job"])
user = nil -- 사용이 끝나면 GC(Garbage Collector)에게 메모리를 반환하기 위해 nil을 대입한다
REMARK. 테이블 변수의 사용이 끝나면 꼭 nil 처리를 하도록 한다. 그렇지 않으면 GC에서 메모리 수거를 하지 못한다.
테이블의 키값을 멤버 변수와 같은 형태로 사용하는 것도 가능하다.
user = {} -- 테이블 변수 선언
user.name = "Jason"
user.age = 10
print(user["name"])
print(user["age"])
테이블 초기화
중괄호({})에서 바로 초기화 가능
// 배열 형식 초기화
a = { "A", "B", "C" }
// 맵 형식 초기화
user = {
name = "Jason",
age = 10,
job = "officer"
}
테이블 순회
a = { "A", "B", "C", nil, nil }
print("length of table:"..#a)
for i = i, #a do
print(a[i])
end
출력 :
length of table:3
A
B
C
-- key-value pair 형태 순회
local dict = {name="Tom", age = 30, job = "Officer"}
for key, value in pairs(dict) do
print(key..","..value)
end
REMARK. 루아는 테이블의 끝을 nil값으로 판단한다. 위 예제 테이블은 5개의 요소를 가지고 있지만 lenth 연산자(#)로는 3번째 까지 밖에 접근할 수 없다.
조건문
if 조건1 then
-- 조건1이 true면 then과 end(또는 elseif) 사이의 내용 실행
elseif 조건2 then
-- 조건2가 true면 then과 end 사이의 내용 실행
else
-- if와 elseif 모두 false면 else와 end 사이의 내용 실행
end
반복문
while
while 조건
do
...
end
repeat
C/C++의 do ~ while 문 처럼, 선 실행 후 조건을 판단한다.
repeat
...
until 조건
for
-- 수치 for문
for 변수 = 초기값, 종료값 [,증가값] do
-- 수치 for문에서는 초기값, 종료값, 증가값을 정의
end
-- 일반(Generic) 배열 for문. ipairs에 배열 형태 테이블 사용
local arr = { "A", "B", "C", "D", "E" }
for index, value in ipairs(arr) do
print(index, value)
end
-- 일반(Generic) 딕셔너리 for문. pairs에 딕셔너리 형태 테이블 사용
local dict = {name="Jason", age=10, job="Officer"}
for key, value in pairs(dict) do
print(key, value)
end
반복 종료
반복을 종료할 때는 break
연산자
산술 연산자
| 연산자 | 설명 |
| + | 더하기 |
| - | 빼기 |
| * | 곱하기 |
| / | 나누기 |
| // | 나눈 후 몫만 취함 |
| % | 나눈 후 나머지만 취함 |
| ^ | 지수 |
관계 연산자
| 연산자 | 설명 |
| = | 선언 |
| == | 같다 |
| ~= | 다르다 |
| > | 좌항이 우항 보다 크다 |
| < | 좌항이 우항 보다 작다 |
| >= | 좌항이 우항 보다 크거나 같다 |
| <= | 좌항이 우항 보다 작거나 같다 |
논리 연산자
| 연산자 | 설명 |
| # | 테이블의 길이(nil은 포함되지 않는다) |
| .. | 문자열 합치기 |
local a = {"Hello", "World"}
print(#a) -- 2
print(a[1].."! "..a[2]) -- Hello! World
메타 테이블
function Enum(t)
local enum = { _props = {} }
for key, value in pairs(t) do
enum._props[key] = value
end
local meta = {
__index = function(self, key)
local value = self._props[key]
if nil == value then
error("<"..key.."> is not exist")
return
end
return value
end,
__newindex = function(self, key, value)
error("Enum is not mutable")
end
}
setmetatable(enum, meta)
return enum
end
OrderType = Enum({
None = 0,
First = 1,
Second = 2
})
print(OrderType.None) -- 0
print(OrderType.First) -- 1
print(OrderType.Second) -- 2
OrderType["Third"] = 10 -- error : Enum is not mutable
print(OrderType.Third) -- error : <Third> is not exist
Rect = {
Create = function(self, x, y, width, height)
local rect = {
x = x or 0,
y = y or 0,
width = width or 0,
height = height or 0,
Contains = function(self, point)
return true
end,
Overlaps = function(self, other)
if self.xMax < other.xMin then return false end
if self.xMin > other.xMax then return false end
if self.yMax < other.yMin then return false end
if self.yMin > other.yMax then return false end
return true
end
}
setmetatable(rect, self)
return rect
end,
xMin = function(self)
return self.x
end,
xMax = function(self)
return self.x + self.width
end,
yMin = function(self)
return self.y
end,
yMax = function(self)
return self.y + self.height
end,
center = function(self)
-- The position of the center of the rectangle.
return 0
end,
max = function(self)
-- The position of the maximum corner of the rectangle.
return 1
end,
min = function(self)
-- The position of the minimum corner of the rectangle.
return 2
end,
position = function(self)
-- The X and Y position of the rectangle.
return 3
end,
size = function(self)
-- The width and height of the rectangle.
return 4
end,
__index = function(self, key)
local prop = Rect[key]
return prop(self)
end
}
local rect = Rect:Create(10, 2, 20, 30)
print(rect.xMin, rect.xMax)
print(rect.yMin, rect.yMax)
print(rect.center, rect.position, rect.size)
local a = Rect:Create(10, 10, 10, 10)
local b = Rect:Create(15, 15, 10, 10)
local c = Rect:Create(21, 21, 10, 10)
print(a:Overlaps(b))
print(a:Overlaps(c))
print(b:Overlaps(c))
setmetatable을 통해 기존 테이블에 새로운 메타 테이블을 할당하면, 덮어 쓰는 것이 아니라 기존 메타 테이블에 추가하게 된다.
local x = { name = "Jason" }
local meta = { __index = {age = 10} }
setmetatable(x, meta)
print(x.name) -- 원래 x가 가지고 있던 name
print(x.age) -- meta 데이터에 의해 추가된 age
부록 1. 같이 읽으면 좋은 글
- 메타테이블 관련 아티클 : https://create.roblox.com/docs/ko-kr/luau/metatables