산술 메타메서드
메타메서드로 +,-,*,/ 및 기타 연산자의 동작을 재정의합니다.
산술 메타메서드은(는) CoddyKit의 무료 Lua Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Lua Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Lua Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
메타메서드 이름
Lua는 모든 산술 연산자에 대한 메타메서드를 정의합니다. Lua가 테이블에 대한 산술 연산을 발견하면 테이블의 메타테이블에서 해당 메타메서드를 찾습니다. 두 피연산자가 모두 테이블이면 Lua는 먼저 왼쪽 피연산자의 메타테이블을 확인합니다.
-- Operator -> Metamethod
-- a + b -> __add
-- a - b -> __sub
-- a * b -> __mul
-- a / b -> __div
-- a % b -> __mod
-- a ^ b -> __pow
-- a // b -> __idiv
-- -a -> __unm (unary minus)
-- #a -> __len
print("Metamethods defined for all Lua operators")벡터 덧셈을 위한 __add
벡터 테이블에 __add를 정의하면 +를 사용할 수 있습니다. 메타메서드는 두 피연산자를 받아 새 값을 반환합니다. 두 피연산자가 모두 테이블일 수도 있고 하나가 숫자일 수도 있으므로, 메타메서드가 두 경우를 모두 처리해야 합니다.
local Vec = {}
Vec.__index = Vec
Vec.__add = function(a, b)
return setmetatable({x=a.x+b.x, y=a.y+b.y}, Vec)
end
Vec.__tostring = function(v)
return string.format("Vec(%g,%g)", v.x, v.y)
end
function Vec.new(x,y) return setmetatable({x=x,y=y},Vec) end
local v1 = Vec.new(1,2)
local v2 = Vec.new(3,4)
print(tostring(v1 + v2)) -- Vec(4,6)__sub __mul __div
__sub, __mul, __div도 같은 방식으로 정의하십시오. 곱셈에서는 메타메서드 내부에서 피연산자의 형식을 확인하여 table*table과 table*number 경우를 모두 처리하십시오.
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__sub = function(a,b) return V(a.x-b.x, a.y-b.y) end
Vec.__mul = function(a,b)
if type(a)=="number" then return V(a*b.x, a*b.y)
elseif type(b)=="number" then return V(a.x*b, a.y*b)
else return a.x*b.x + a.y*b.y -- dot product
end
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end
local v = V(3,4)
print(tostring(v * 2)) -- (6,8)
print(tostring(V(1,0) - V(0,1))) -- (1,-1)__unm 단항 마이너스
__unm은 Lua가 -obj를 계산할 때 호출되는 단항 마이너스 메타메서드입니다. 피연산자를 받아(일관성을 위해 같은 값이 두 번 전달됩니다) 음수로 바꾼 값을 반환합니다.
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__unm = function(a) return V(-a.x, -a.y) end
Vec.__tostring = function(v)
return string.format("(%g,%g)", v.x, v.y)
end
local v = V(3, -4)
print(tostring(-v)) -- (-3,4)
print(tostring(-(-v))) -- (3,-4)사용자 지정 길이를 위한 __len
정수로 이루어진 연속 구간이 원시 형태로 없는 테이블에서 #obj를 계산하면 __len이 호출됩니다. 집합, 큐 또는 가중치 컨테이너 같은 사용자 지정 형식에 의미 있는 "길이"를 반환하도록 정의하십시오.
local Bag = {}
Bag.__index = Bag
Bag.__len = function(b) return b._count end
function Bag.new()
return setmetatable({_count=0, _items={}}, Bag)
end
function Bag:add(item, qty)
self._items[item] = (self._items[item] or 0) + (qty or 1)
self._count = self._count + (qty or 1)
end
local bag = Bag.new()
bag:add("apple", 3)
bag:add("banana", 2)
print(#bag) -- 5__mod와 __pow
__mod는 % 연산자를 처리하고, __pow는 ^ 연산자를 처리합니다. 자주 사용되지는 않지만 큰 정수, 분수 또는 모듈러 산술 객체 같은 사용자 지정 숫자 형식에 유용합니다.
local Modular = {}
Modular.__index = Modular
local M = 1000000007
local function mod(n)
return setmetatable({n = n % M}, Modular)
end
Modular.__add = function(a,b) return mod(a.n + b.n) end
Modular.__mul = function(a,b) return mod(a.n * b.n) end
Modular.__pow = function(a,b)
local r, base, exp = mod(1), a, b
while exp > 0 do
if exp%2==1 then r = r*base end
base = base*base; exp = math.floor(exp/2)
end
return r
end
print((mod(2) ^ 30).n) -- 73741817 (2^30 mod 1e9+7)__concat
적어도 하나의 피연산자가 이 메타메서드를 가지고 있으면 __concat이 .. 연산자에 의해 호출됩니다. 이를 통해 사용자 지정 형식의 연결을 정의하거나 유창한 DSL을 만들 수 있습니다.
local Builder = {}
Builder.__index = Builder
Builder.__concat = function(a, b)
local result = {}
for _, v in ipairs(a._parts) do result[#result+1] = v end
if type(b) == "string" then result[#result+1] = b
else for _, v in ipairs(b._parts) do result[#result+1] = v end end
return setmetatable({_parts=result}, Builder)
end
Builder.build = function(b) return table.concat(b._parts) end
local function S(s) return setmetatable({_parts={s}},Builder) end
print((S("Hello") .. ", " .. S("World") .. "!"):build())비교 메타메서드
__eq는 테이블의 ==을 정의합니다(두 피연산자가 같은 메타테이블을 가질 때만 호출됩니다). __lt는 <를, __le는 <=를 정의합니다. 참고로 ~=는 __eq를 사용하고, >는 인자를 뒤집은 __lt를 사용하며, >=는 __le를 사용합니다.
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__eq = function(a,b) return a.x==b.x and a.y==b.y end
Vec.__lt = function(a,b)
return (a.x^2+a.y^2) < (b.x^2+b.y^2) -- by magnitude
end
print(V(1,2) == V(1,2)) -- true
print(V(1,2) == V(1,3)) -- false
print(V(1,0) < V(2,0)) -- true (1 < 2)메타메서드 연결
메타메서드는 값을 반환하며 보통 새 테이블을 반환하므로 연산을 자연스럽게 연결할 수 있습니다. 각 연산자는 새 객체를 반환하고 다음 연산자는 그 결과를 사용합니다. 이를 통해 사용자 지정 형식에서도 유창한 산술 표현식을 사용할 수 있습니다.
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__add = function(a,b) return V(a.x+b.x,a.y+b.y) end
Vec.__mul = function(a,b)
if type(b)=="number" then return V(a.x*b,a.y*b) end
return V(a.x*b.x+a.y*b.y, 0) -- simplified
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end
local result = V(1,0) + V(0,1) * 3
print(tostring(result)) -- (1,3)혼합 형식 연산
vec * 2를 작성하면 왼쪽 피연산자는 테이블입니다. 2 * vec를 작성하면 왼쪽 피연산자가 숫자이므로(메타메서드가 없음) Lua는 오른쪽 피연산자의 메타테이블에서 __mul을 확인합니다. 메타메서드에서 두 피연산자 순서를 모두 처리하십시오.
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__tostring = function(v) return "("..v.x..","..v.y..")" end
Vec.__mul = function(a, b)
if type(a) == "number" then
return V(a*b.x, a*b.y) -- scalar * vec
elseif type(b) == "number" then
return V(a.x*b, a.y*b) -- vec * scalar
end
return a.x*b.x + a.y*b.y -- dot product
end
print(tostring(V(1,2) * 3)) -- (3,6)
print(tostring(3 * V(1,2))) -- (3,6)빠른 확인
-myTable에 의해 호출되는 메타메서드는 무엇일까요?
복습: 산술 메타메서드
요약:
__add __sub __mul __div __mod __pow __idiv— 이항 산술__unm— 단항 마이너스,__len— # 연산자__concat—..연산자__eq __lt __le— 비교 연산자- 메타메서드 내부에서 혼합 형식(숫자/테이블)을 처리하십시오
자주 묻는 질문
“산술 메타메서드” 강의는 무료인가요?
네 — “산술 메타메서드” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Lua Academy 강의 전체를 잠금 해제할 수 있습니다. Lua Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“산술 메타메서드”에서 뭘 배우나요?
메타메서드로 +,-,*,/ 및 기타 연산자의 동작을 재정의합니다. 브라우저에서 직접 실행하는 실습 코드로 Lua Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Lua Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Lua Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“산술 메타메서드” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Lua Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Lua Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.