0Pricing
Lua Academy · 강의

메타테이블 입문

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_1

setmetatable과 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))   -- Lua

rawget과 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 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 메타테이블 입문
  2. __index와 __newindex
  3. 산술 메타메서드
  4. __tostring과 __len
← Lua Academy(으)로 돌아가기