루아우 가이드
개요
OVERDARE Studio는 Lua를 기반으로 확장된 스크립팅 언어인 Luau를 사용합니다. Luau는 Lua와 대부분의 문법과 기능을 그대로 유지하면서도, 타입 선언과 타입 추론, 복합 대입 연산자, 단축 if 표현식 등 다양한 기능이 추가되어 있습니다.
이러한 확장 덕분에 개발자는 더 안전하고 유연한 방식으로 로직을 구성할 수 있으며, 높은 수준의 생산성과 표현력을 동시에 확보할 수 있습니다.
특이사항
local을 명시하지 않은 변수와 함수는 여전히 글로벌 스코프에 선언되며, 전역에서 접근 가능합니다.
타입 명시에 따른 자동 완성 기능은 현재 부분적으로만 지원되며, 일부 정보는 자동 완성 목록에 표시되지 않을 수 있습니다.
타입 추론 기능은 현재 부분적으로만 지원되며, 일부 타입은 제대로 인식하지 못할 수 있습니다.
타입 선언
변수
local 변수를 선언할 때, 변수명 뒤에 아래와 같이 타입을 지정할 수 있습니다. (글로벌 변수 선언에는 사용할 수 없습니다.)
local Gold: number = 1
함수
함수의 인자나 반환값에도 아래와 같이 타입을 지정할 수 있습니다. (글로벌 함수에도 사용할 수 있습니다.)
local function Sum(a: number, b: number): number
return a + b
end
print(Sum(1, 2))
function AddScalarToVector3(v: Vector3, scalar: number): Vector3
return Vector3.new(v.X + scalar, v.Y + scalar, v.Z + scalar)
end
local Pos = Vector3.new(50, 0, 10)
print(AddScalarToVector3(Pos, 100))
가변 인자 함수
...와 같은 가변 인자에도 타입을 지정할 수 있습니다.
--!nonstrict
local function Sum(...: number): number
local t, result = {...}, 0
for i = 1, #t do
result += t[i]
end
return result
end
print(Sum(1, 2, 2, 5))
테이블
테이블 타입은 {}로 정의하며, 중괄호 안에 각 필드의 타입을 명시함으로써 테이블에 구성되는 값의 타입을 고정할 수 있습니다.
--!nonstrict
local SomeList: {} = { 1, false, "Hello" }
local NumberList: { number } = { 1, 2, 3, 4, 5 }
NumberList[2] = false -- Type 'boolean' could not be converted into 'number'
테이블 타입은 키와 값의 타입을 각각 정의할 수도 있습니다.
local BoolList: { [string]: boolean } =
{
Key1 = false,
Key2 = true
}
BoolList["Key2"] = 2 -- Type 'number' could not be converted into 'boolean'
인스턴스
Player나 Part, Instance 같은 객체도 타입을 지정할 수 있습니다.
--!nonstrict
local function InitPlayer(player: Player)
player:SetAttribute("Score", 0)
end
local function SetRandomColor(target: Part)
local r = math.random(1, 255)
local g = math.random(1, 255)
local b = math.random(1, 255)
target.Color = Color3.fromRGB(r, g, b)
end
local function RemoveAllAttributes(target: Instance)
for key, value in target:GetAttributes() do
target:SetAttribute(key, nil)
end
end
타입 검사
자동 완성 연동
변수나 함수에 타입을 선언하면, 코드를 작성할 때 자동 완성 기능에 타입 정보가 함께 표시되어 오류를 사전에 방지하고 코드의 유지보수성을 높일 수 있습니다.

타입 추론 모드
스크립트 상단에서 --!nonstrict와 같이 타입 추론 모드를 지정할 수 있습니다.
--!nocheck (기본값)
타입 검사를 완전히 비활성화합니다.
--!nonstrict
명시적으로 지정된 타입에 대해서만 검사합니다.
--!strict
모든 코드에 대해 타입을 추론 및 검사합니다.
--!nocheck
기본 상태로 타입 검사가 동작하지 않습니다. (타입 오류가 있어도 무시되며, 타입 추론이나 경고도 발생하지 않습니다.)

--!nonstrict
명시적으로 지정된 타입에 대해서만 검사하며, 타입을 지정하지 않은 변수나 함수는 검사하지 않습니다.

--!strict
모든 코드에 대해 타입을 추론 및 검사하며, 타입이 명시되지 않은 경우에도 자동으로 추론하여 오류를 검출합니다.

유연한 타입 구조
선택적 타입
타입 뒤에 ?를 붙이면 해당 타입을 선택 사항으로 만들 수 있습니다. 선택 사항으로 지정된 타입은 명시된 타입과 nil 값을 모두 허용합니다.
--!nonstrict
local NumOrNil: number? = 1
NumOrNil = nil
local Num: number = 1
Num = nil -- Type 'nil' could not be converted into 'number'
타입 캐스트
서로 다른 타입의 변수에 값을 할당하면 오류가 발생할 수 있습니다. 이 경우 :: 연산자를 사용하여 명시적으로 타입 캐스팅하면 타입 오류를 피할 수 있습니다.
--!nonstrict
local SomeNum: number = 100
local NumToString1: string = SomeNum::any
local NumToString2: string = SomeNum -- Type 'number' could not be converted into 'string'
리터럴 타입 지정
string이나 boolean은 리터럴 타입을 지정해 상수처럼 사용할 수 있습니다.
--!nonstrict
local SomeString: "ConstString" = "ConstString"
local SomeBoolean: true = true
SomeString = "Test" -- Type '"Test"' could not be converted into ''"ConstString"''
SomeBoolean = false -- Type 'false' could not be converted into 'true'
유니언과 교차 타입
유니언과 교차 타입을 사용하면, 하나의 변수에 여러 타입을 허용하거나, 여러 타입을 조합해 새로운 복합 타입을 정의할 수 있습니다.
유니언 타입은 | 연산자를 사용하여 여러 타입 중 하나의 값을 가질 수 있도록 합니다.
--!nonstrict
local NumberOrString: number | string = 10
NumberOrString = "Test"
NumberOrString = false -- Type 'boolean' could not be converted into 'number | string'; none of the union options are compatible
local SomeString: "Hello" | "World" = "Hello"
SomeString = "World"
SomeString = "Test" -- Type '"Test"' could not be converted into '"Hello" | "World"'; none of the union options are compatible
교차 타입은 & 연산자를 사용하여 여러 타입을 조합한 복합 객체를 정의할 수 있습니다. (type 키워드를 사용하여 각각의 타입을 먼저 정의한 후 조합해야 합니다.)
type Type1 = { Name: string }
type Type2 = { Value: number }
local StringAndNumber: Type1 & Type2 = { Name = "Hello", Value = 10 }
local StringAndNumber: Type1 & Type2 = { Name = "Hello", OtherKey = 10 }
--[[
Type
'StringAndNumber'
could not be converted into
'Type1 & Type2'
caused by:
Not all intersection parts are compatible.
Table type 'StringAndNumber' not compatible with type 'Type2' because the former is missing field 'Value'
]]--
구문 및 표현식
복합 대입 연산자
아래 표에 나열된 복합 대입 연산자를 사용하면, 연산과 대입을 하나의 구문으로 처리할 수 있어 코드를 더 간결하고 효율적으로 작성할 수 있습니다.
단, 다른 언어와 달리 print(a += 2)와 같은 표현식 내에서는 사용할 수 없으며, 반드시 a += 2처럼 별도의 문으로 분리해서 작성해야 합니다.
+=
a = a + b
-=
a = a - b
*=
a = a * b
/=
a = a / b
//=
a = a // b
%=
a = a % b
^=
a = a ^ b
..=
a = a .. b
local Value = 3
Value += 1 -- 4
local Value = 3
Value -= 1 -- 2
local Value = 3
Value *= 2 -- 6
local Value = 3
Value /= 2 -- 1.5
local Value = 3
Value //= 2 -- 1
local Value = 3
Value %= 2 -- 1
local Value = 3
Value ^= 2 -- 9
local Text = "Hello"
Text ..= " World!" -- Hello World!
단축 if
리터럴 값을 조건 분기 내에 삽입하여, 조건에 따라 즉시 값을 반환할 수 있습니다.
local RandomNum = math.random(1, 2)
local Result = if RandomNum == 1 then "true" else "false"
print(RandomNum, " -> ", Result)
continue 키워드
for나 while과 같은 반복문 내에서 continue 키워드를 사용하면, 현재 반복을 건너뛰고 다음 반복으로 즉시 넘어갈 수 있습니다.
for i = 1, 5 do
if i > 3 then
continue
end
print(i)
end
문자열 보간
backticks(`)을 사용하여 중괄호 내에 변수나 표현식을 동적으로 삽입할 수 있습니다.
local ItemName = "Sword"
local ItemPrice = 2000
print(`ItemName : {ItemName} / ItemPrice : {ItemPrice}`) -- ItemName : Sword / ItemPrice : 2000
반복문
Generic For Loops
ipairs나 pairs와 같은 반복자를 명시적으로 사용하지 않아도, for ... in 구문을 통해 테이블과 같은 컬렉션을 직접 순회할 수 있으며, 배열이나 딕셔너리 형태에도 적용할 수 있습니다.
local NumberList = { 1, 2, 3 }
for key, value in NumberList do
print(key, " : ", value)
end
local PlayerData =
{
Name = "Player",
Level = 5,
IsValid = true,
EquipItemIDList =
{
1, 3
}
}
for key, value in PlayerData do
print(key, " : ", value)
end
Generalized Iteration
__iter 메타메서드를 사용하면, 테이블 자체에 반복자 로직을 내장시켜 사용자 정의 순회 동작을 구현할 수 있습니다.
--!nonstrict
local NumberList = { 1, 5, 11, 4, 9 }
local SortedIterator =
{
__iter = function(t)
local sorted = table.clone(t)
table.sort(sorted)
local i = 0
return function()
i += 1
if i <= #sorted then
return i, sorted[i]
end
end
end
}
setmetatable(NumberList, SortedIterator)
for key, value in NumberList do
print(key, " : ", value)
end
사용자 정의 타입
Type
type 키워드로 사용자 정의 타입을 선언할 수 있으며, 이를 통해 몬스터, 스킬, 타일 등 복잡한 데이터 구조를 보다 효율적이고 안전하게 관리할 수 있습니다.
--!nonstrict
type Car =
{
Name: string,
Speed: number,
Drive: (Car, boolean) -> () -- function
}
local function DriveFunc(self, useBooster)
print(self.Name, "Speed : ", self.Speed, " / useBooster : ", useBooster)
end
local Taxi: Car =
{
Name = "Taxi",
Speed = 30,
Drive = DriveFunc
}
Taxi:Drive(true)
또한, 하나의 함수 타입을 여러 함수에 재사용함으로써 함수 구조를 일관되게 유지를 유지하고, 다양한 기능을 확장하는 데 활용할 수 있습니다.
--!nonstrict
type MathFunc = (number, number) -> number
local Sum: MathFunc = function(a, b)
return a + b
end
local Multiply: MathFunc = function(a, b)
return a * b
end
Type Exports
export type 키워드를 사용하면, 모듈 스크립트 내에서 정의한 타입들을 외부에서 사용할 수 있도록 분리하여 관리할 수 있습니다.
--!nonstrict
export type Item =
{
Name: string,
Price: number
}
export type Skill =
{
Name: string,
IsActiveSkill: boolean
}
--!nonstrict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ModuleScript = require(ReplicatedStorage.ModuleScript)
local SomeItem: ModuleScript.Item =
{
Name = "Sword",
Price = 10
}
print(SomeItem)
local SomeSkill: ModuleScript.Skill =
{
Name = "FireBall",
IsActiveSkill = true
}
print(SomeSkill)
Generic
제네릭
<T>를 이용한 제네릭 타입을 정의하면, 입력되는 타입을 동적으로 지정할 수 있어 하나의 타입 정의로 다양한 형태의 데이터를 유연하게 표현하고 재사용할 수 있습니다.
--!nonstrict
type SomeData<T> =
{
Name: string,
Value: T
}
local NumberData: SomeData<number> =
{
Name = "Test1",
Value = 15
}
print(NumberData.Name, " / ", NumberData.Value)
local BooleanData: SomeData<boolean> =
{
Name = "Test1",
Value = false
}
print(BooleanData.Name, " / ", BooleanData.Value)
함수 제네릭
함수의 매개변수에 제네릭을 활용하면 전달되는 데이터의 타입을 호출 시점에 동적으로 지정할 수 있어, 코드 재사용성과 타입 안정성을 동시에 확보할 수 있습니다.
--!nonstrict
type SomeList<T> = { T }
local NameList: SomeList<string> = { "Bob", "Dan", "Mary" }
local NumberList: SomeList<number> = { 1, 2, 3 }
local function printList<T>(list: SomeList<T>)
for key, value in list do
print(key, " : ", value)
end
end
printList(NameList)
printList(NumberList)
라이브러리
Lua의 기본 라이브러리 중에서 io, package 등이 제거되고, table, string 등의 기능이 확장되었습니다. (라이브러리에 대한 자세한 내용은 추후 제공될 예정입니다.)
Table 복제 기능
local T1 = { 1, 2, 3 }
local T2 = table.clone(T1)
T1[1] = 10
print(T1[1])
print(T2[1])
문자열 Split 기능
local SomeString = "Hello,World"
local Splits = SomeString:split(",")
print(Splits[1], Splits[2])
Coroutine 종료
local co = coroutine.create(function()
for i = 1, 5 do
wait(1)
print(i)
end
end)
coroutine.resume(co)
wait(4)
coroutine.close(co)
Task
local SomeTask = task.spawn(function()
for i = 1, 10 do
wait(2)
print(i)
end
end)
print("wait 5s")
local elapsed = task.wait(5)
task.cancel(SomeTask)
print("cancel! / elapsed : ", elapsed)
자세히 알아보기
task로 편리하게 coroutine 제어하기Last updated