Metamethody arytmetyczne
Proszę przeciążać operatory +, -, *, / i inne za pomocą metametod.
Metamethody arytmetyczne to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.
Nazwy metametod
Lua definiuje metametody dla wszystkich operatorów arytmetycznych. Gdy Lua napotka operację arytmetyczną na tabeli, szuka odpowiadającej jej metametody w metatabeli tabeli. Jeśli oba operandy są tabelami, Lua najpierw sprawdza metatabelę lewego operandu.
-- 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 do dodawania wektorów
Zdefiniuj __add dla tabeli wektora, aby obsługiwać operator +. Metametoda otrzymuje dwa operandy i zwraca nową wartość. Oba operandy mogą być tabelami albo jeden z nich może być liczbą — metametoda powinna obsługiwać oba przypadki.
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
Zdefiniuj podobnie __sub, __mul i __div. W przypadku mnożenia obsłuż zarówno table*table, jak i table*number, sprawdzając typy operandów wewnątrz metametody.
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 — negacja jednoargumentowa
__unm to metametoda negacji jednoargumentowej, wywoływana, gdy Lua oblicza -obj. Otrzymuje operand (dla zachowania spójności ta sama wartość jest przekazywana dwukrotnie) i zwraca wartość z przeciwnym znakiem.
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 dla niestandardowej długości
__len jest wywoływane podczas obliczania #obj dla tabeli, która nie zawiera surowej sekwencji liczb całkowitych. Zdefiniuj je tak, aby zwracało znaczącą „długość” dla niestandardowych typów, takich jak zbiory, kolejki lub kontenery ważone.
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 i __pow
__mod obsługuje operator %, a __pow operator ^. Są one rzadziej używane, ale przydatne dla niestandardowych typów liczbowych, takich jak duże liczby całkowite, ułamki lub obiekty arytmetyki modularnej.
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 jest wywoływane przez operator .., gdy co najmniej jeden operand ma tę metametodę. Umożliwia to definiowanie konkatenacji dla niestandardowych typów lub tworzenie płynnych DSL-i.
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())Metametody porównań
__eq definiuje == dla tabel (jest wywoływane tylko wtedy, gdy oba operandy mają tę samą metatabelę). __lt definiuje <, a __le definiuje <=. Uwaga: ~= używa __eq; > używa __lt z odwróconymi argumentami; >= używa __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)Łączenie metametod
Ponieważ metametody zwracają wartości (zwykle nowe tabele), operacje można w naturalny sposób łączyć. Każdy operator zwraca nowy obiekt, a kolejny operator używa tego wyniku. Umożliwia to tworzenie płynnych wyrażeń arytmetycznych dla niestandardowych typów.
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)Operacje na mieszanych typach
Gdy zapiszesz vec * 2, lewy operand jest tabelą. Gdy zapiszesz 2 * vec, lewy operand jest liczbą (bez metametody), więc Lua sprawdza metatabelę prawego operandu pod kątem __mul. W metametodzie obsłuż oba porządki operandów.
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)Szybkie sprawdzenie
Jaka metametoda jest wywoływana przez -myTable?
Podsumowanie: metametody arytmetyczne
Podsumowanie:
__add __sub __mul __div __mod __pow __idiv— dwuargumentowe operacje arytmetyczne__unm— negacja jednoargumentowa;__len— operator #__concat— operator..__eq __lt __le— operatory porównań- Obsługuj mieszane typy (liczba/tabela) wewnątrz metametod
Często zadawane pytania
Czy lekcja „Metamethody arytmetyczne” jest bezpłatna?
Tak — pełny tekst „Metamethody arytmetyczne” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Metamethody arytmetyczne”?
Proszę przeciążać operatory +, -, *, / i inne za pomocą metametod. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Lua Academy?
Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Metamethody arytmetyczne”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?
Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wprowadzenie do metatabel
- __index i __newindex
- Metamethody arytmetyczne
- __tostring i __len