메타테이블 입문
setmetatable/getmetatable로 메타테이블을 설정하고 가져옵니다.
메타테이블 입문은(는) CoddyKit의 무료 Lua Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Lua Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Lua Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
메타테이블이란 무엇입니까
metatable은 다른 테이블의 동작을 제어하는 일반 Lua 테이블입니다. Lua가 테이블에서 수행할 수 없는 연산(예: 산술 연산이나 없는 키에 대한 인덱싱)을 만나면 metatable에서 해당 메타메서드를 찾습니다. 이는 연산자 오버로딩과 객체 지향 프로그래밍을 지원하는 Lua의 확장 방식입니다.
local t = {}
local mt = {__index = function(_, k) return "default_" .. k end}
setmetatable(t, mt)
print(t.foo) -- default_foo
print(t.bar) -- default_bar
print(t[1]) -- default_1setmetatable과 getmetatable
setmetatable(t, mt)는 t의 metatable을 mt로 설정하고 t를 반환합니다. getmetatable(t)는 metatable을 반환하며, 없으면 nil을 반환합니다. mt.__metatable = "protected"로 설정하면 metatable이 변경되지 않도록 보호할 수 있습니다.
local t = {x = 10}
local mt = {}
setmetatable(t, mt)
print(getmetatable(t) == mt) -- true
-- Protect metatable
mt.__metatable = "locked"
print(getmetatable(t)) -- locked
-- setmetatable(t, {}) -- ERROR: cannot change protected metatable테이블로 사용하는 __index
__index가 테이블이면 Lua는 해당 테이블에서 없는 키를 찾습니다. 이는 Lua 프로토타입 상속의 기반입니다. __index에도 키가 없으면 Lua는 그 테이블의 metatable을 확인하는 방식으로 연결된 상위 테이블까지 계속 확인합니다.
local Animal = {sound = "...", legs = 4}
local Dog = setmetatable({sound = "Woof"}, {__index = Animal})
local Cat = setmetatable({sound = "Meow"}, {__index = Animal})
print(Dog.sound) -- Woof (own field)
print(Dog.legs) -- 4 (from Animal)
print(Cat.sound) -- Meow
print(Cat.legs) -- 4함수로 사용하는 __index
__index가 함수이면 Lua는 테이블과 없는 키를 인수로 함수를 호출합니다. 함수는 값을 동적으로 계산하거나 가져올 수 있습니다. 키를 찾지 못했다는 것을 나타내려면 __index에서 nil을 반환하십시오.
local dynamic = setmetatable({}, {
__index = function(t, k)
if k:sub(1,4) == "get_" then
local field = k:sub(5)
return function(self) return self[field] end
end
return nil
end
})
dynamic.name = "Lua"
local getter = dynamic.get_name
print(getter(dynamic)) -- Luarawget과 rawset
rawget(t, k)는 __index를 실행하지 않고 테이블 키를 읽습니다. rawset(t, k, v)는 __newindex를 실행하지 않고 키를 설정합니다. 메타메서드 내부에서 무한 재귀를 피하기 위해 테이블에 직접 접근해야 할 때 메타메서드를 우회하는 용도로 사용하십시오.
local logged = setmetatable({}, {
__newindex = function(t, k, v)
print("Setting", k, "=", v)
rawset(t, k, v) -- bypass __newindex
end
})
logged.x = 10 -- Setting x = 10
logged.x = 20 -- no log! key now exists in t
print(logged.x) -- 20메타테이블을 공유하는 여러 테이블
하나의 메타테이블을 여러 테이블이 공유할 수 있습니다. 이것이 Lua의 클래스 시스템이 작동하는 방식입니다. 한 클래스의 모든 인스턴스가 메서드를 담고 있는 동일한 메타테이블을 공유합니다. 메타테이블을 변경하면 모든 인스턴스에 영향을 줍니다.
local Mt = {
__index = {
greet = function(self)
print("Hello from " .. (self.name or "?"))
end
}
}
local a = setmetatable({name="Alice"}, Mt)
local b = setmetatable({name="Bob"}, Mt)
a:greet() -- Hello from Alice
b:greet() -- Hello from Bob__metatable 필드
mt.__metatable에 어떤 값이든 설정하면 getmetatable은 실제 메타테이블 대신 해당 값을 반환합니다. 이렇게 하면 사용자가 메타테이블을 검사하거나 교체하지 못하게 할 수 있어 캡슐화와 보안에 유용합니다.
local secret = setmetatable({}, {
__metatable = false, -- hide metatable
__index = {value = 42}
})
print(secret.value) -- 42
print(getmetatable(secret)) -- false (not the real mt)
-- setmetatable(secret, {}) -- ERROR메타테이블 확인
getmetatable(t)을 사용하면 객체에 특정 메타테이블이 있는지 확인할 수 있습니다(형식 확인에 사용). __metatable이 실제 메타테이블을 가릴 수 있으므로, 신뢰할 수 있는 isinstance 확인을 위해 rawequal 또는 표시 필드를 사용하십시오.
local MyClass = {}
MyClass.__index = MyClass
MyClass.__metatable = MyClass -- use self as marker
function MyClass.new(x)
return setmetatable({x=x}, MyClass)
end
local obj = MyClass.new(5)
print(getmetatable(obj) == MyClass) -- true
print(obj.x) -- 5테이블이 아닌 값의 메타테이블
Lua의 문자열에는 이미 메타테이블(string 모듈)이 있습니다. 따라서 모든 문자열에서 s:upper()를 호출할 수 있습니다. 순수 Lua에서는 문자열, 숫자 또는 불리언에 메타테이블을 설정할 수 없으며, 테이블과 사용자 데이터에만 설정할 수 있습니다.
local s = "hello"
local mt = getmetatable(s)
-- String metatable has __index = string library
print(mt.__index == string) -- true
-- So all string functions are methods:
print(s:upper()) -- HELLO
print(s:rep(3, "-")) -- hello-hello-hello메타테이블을 사용한 디버깅
__tostring 메타메서드를 추가하면 테이블을 tostring()과 print()가 표시하는 방식을 제어할 수 있습니다. 복잡한 객체를 디버깅할 때 매우 유용합니다.
local Point = {}
Point.__index = Point
Point.__tostring = function(p)
return string.format("Point(%g, %g)", p.x, p.y)
end
function Point.new(x, y)
return setmetatable({x=x,y=y}, Point)
end
local p = Point.new(3, 4)
print(tostring(p)) -- Point(3, 4)
print(p) -- Point(3, 4) (print calls tostring)빠른 확인
__index가 다른 테이블로 설정된 메타테이블을 가진 테이블에서 찾을 수 없는 키에 접근하면 어떻게 될까요?
복습: 메타테이블
요약:
setmetatable(t, mt)/getmetatable(t)__index: 테이블 → 프로토타입 조회, 함수 → 동적 디스패치rawget/rawset은 메타메서드를 우회합니다- 메타테이블을 공유하면 클래스와 유사한 동작을 구현할 수 있습니다
__metatable은 메타테이블이 검사되지 않도록 보호합니다__tostring은 출력 방식을 제어합니다
자주 묻는 질문
“메타테이블 입문” 강의는 무료인가요?
네 — “메타테이블 입문” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Lua Academy 강의 전체를 잠금 해제할 수 있습니다. Lua Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“메타테이블 입문”에서 뭘 배우나요?
setmetatable/getmetatable로 메타테이블을 설정하고 가져옵니다. 브라우저에서 직접 실행하는 실습 코드로 Lua Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Lua Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Lua Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“메타테이블 입문” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Lua Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Lua Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.