Wprowadzenie do metatabel
Proszę ustawiać i pobierać metatabele za pomocą setmetatable/getmetatable.
Wprowadzenie do metatabel to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 1 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.
Czym jest metatabela?
Metatabela to zwykła tabela Lua, która steruje zachowaniem innej tabeli. Gdy Lua napotka operację, której nie może wykonać na tabeli (na przykład działanie arytmetyczne lub odczyt brakującego klucza), wyszukuje odpowiednią metametodę w metatabeli. To mechanizm rozszerzania Lua umożliwiający przeciążanie operatorów i programowanie obiektowe.
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 i getmetatable
setmetatable(t, mt) ustawia metatabelę t na mt i zwraca t. getmetatable(t) zwraca metatabelę albo nil, jeśli jej nie ma. Można zabezpieczyć metatabelę przed zmianami, ustawiając mt.__metatable = "protected".
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 jako tabela
Gdy __index jest tabelą, Lua wyszukuje brakujący klucz w tej tabeli. Stanowi to podstawę dziedziczenia prototypowego w Lua. Jeśli klucza nie ma również w __index, Lua sprawdza metatabelę tej tabeli i kontynuuje wyszukiwanie w górę łańcucha.
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 jako funkcja
Gdy __index jest funkcją, Lua wywołuje ją, przekazując tabelę i brakujący klucz. Funkcja może obliczyć wartość lub pobrać ją dynamicznie. Zwróć nil z __index, aby wskazać, że „nie znaleziono klucza”.
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 i rawset
rawget(t, k) odczytuje klucz tabeli bez uruchamiania __index. rawset(t, k, v) ustawia klucz bez uruchamiania __newindex. Używaj tych funkcji, aby ominąć metametody, gdy potrzebujesz bezpośredniego dostępu do tabeli wewnątrz metametody i chcesz uniknąć nieskończonej rekurencji.
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) -- 20Wiele tabel współdzielących metatabelę
Jedna metatabela może być współdzielona przez wiele tabel. Tak działają systemy klas w Lua: wszystkie instancje klasy współdzielą tę samą metatabelę, w której przechowywane są metody. Zmiany w metatabeli wpływają na wszystkie instancje.
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 BobPole __metatable
Ustawienie mt.__metatable na dowolną wartość powoduje, że getmetatable zwraca tę wartość zamiast rzeczywistej metatabeli. Uniemożliwia to użytkownikom sprawdzanie lub zastępowanie metatabeli — jest to przydatne do enkapsulacji i zapewnienia bezpieczeństwa.
local secret = setmetatable({}, {
__metatable = false, -- hide metatable
__index = {value = 42}
})
print(secret.value) -- 42
print(getmetatable(secret)) -- false (not the real mt)
-- setmetatable(secret, {}) -- ERRORSprawdzanie metatabeli
Użyj getmetatable(t), aby sprawdzić, czy obiekt ma określoną metatabelę (na potrzeby sprawdzania typu). Ponieważ __metatable może ukrywać rzeczywistą metatabelę, do niezawodnego sprawdzania w stylu isinstance użyj rawequal lub pola pełniącego funkcję znacznika.
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) -- 5Metatabele obiektów innych niż tabele
Napisy w Lua mają już metatabelę (moduł string). Dlatego na dowolnym napisie można wywołać s:upper(). W czystym Lua nie można ustawiać metatabel napisom, liczbom ani wartościom logicznym — tylko tabelom i userdata.
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-helloDebugowanie za pomocą metatabel
Można dodać metametodę __tostring, aby kontrolować sposób wyświetlania tabeli przez tostring() i print(). Jest to nieoceniona pomoc podczas debugowania złożonych obiektów.
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)Szybkie sprawdzenie
Co się stanie, gdy odczytasz klucz, którego nie ma w tabeli mającej metatabelę z polem __index ustawionym na inną tabelę?
Podsumowanie: metatabele
Podsumowanie:
setmetatable(t, mt)/getmetatable(t)__index: tabela → wyszukiwanie w prototypie; funkcja → dynamiczne przekazywanie wywołańrawget/rawsetomijają metametody- Współdzielone metatabele umożliwiają zachowanie podobne do klas
__metatablechroni metatabelę przed sprawdzaniem__tostringkontroluje wynik wyświetlany przez print
Często zadawane pytania
Czy lekcja „Wprowadzenie do metatabel” jest bezpłatna?
Tak — pełny tekst „Wprowadzenie do metatabel” 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 „Wprowadzenie do metatabel”?
Proszę ustawiać i pobierać metatabele za pomocą setmetatable/getmetatable. Ć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 1 z 4.
Ile czasu zajmuje lekcja „Wprowadzenie do metatabel”?
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