0Pricing
Lua Academy · Lekcja

Klasy za pomocą metatabel

Proszę symulować klasy za pomocą tabel i __index do wyszukiwania metod.

Klasy za pomocą 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.

Wzorzec tabeli klasy

W Lua „klasa” to po prostu tabela przechowująca metody. Instancje są tabelami, których metatabela ma pole __index wskazujące na tabelę klasy. Dzięki temu wszystkie metody są dostępne dla instancji poprzez łańcuch wyszukiwania.

local Animal = {}
Animal.__index = Animal

function Animal.new(name, sound)
  return setmetatable({name=name, sound=sound}, Animal)
end

function Animal:speak()
  print(self.name .. " says " .. self.sound)
end

local dog = Animal.new("Rex","Woof")
dog:speak()  -- Rex says Woof

__index wskazuje na klasę

Ustawienie ClassName.__index = ClassName oznacza: „brakujących kluczy szukaj w tabeli klasy”. Gdy wywoływana jest metoda instancji, Lua nie znajduje jej w instancji, sprawdza metatabelę (__index), odnajduje klasę i wyszukuje w niej metodę.

local Point = {}
Point.__index = Point

Point.type = "2D Point"

function Point.new(x,y)
  return setmetatable({x=x,y=y}, Point)
end

function Point:magnitude()
  return math.sqrt(self.x^2 + self.y^2)
end

local p = Point.new(3,4)
print(p:magnitude())   -- 5.0
print(p.type)          -- 2D Point (from class)

Wzorzec konstruktora

Funkcja new() jest konstruktorem: tworzy tabelę z danymi instancji i zwraca ją opakowaną w metatabelę wskazującą na klasę. Jest to standardowy sposób tworzenia obiektów w Lua.

local Circle = {}
Circle.__index = Circle

function Circle.new(cx, cy, radius)
  assert(radius > 0, "radius must be positive")
  return setmetatable({cx=cx, cy=cy, r=radius}, Circle)
end

function Circle:area()
  return math.pi * self.r^2
end

function Circle:perimeter()
  return 2 * math.pi * self.r
end

local c = Circle.new(0, 0, 5)
print(string.format("Area: %.2f", c:area()))

Składnia metody a składnia funkcji

obj:method() jest skrótem zapisu obj.method(obj). Metody należy definiować za pomocą składni z dwukropkiem (function Cls:method()), aby otrzymać niejawny argument self. Metodę należy wywoływać z dwukropkiem, aby przekazać instancję. Mieszanie kropki i dwukropka prowadzi do trudnych do wykrycia błędów.

local Dog = {}
Dog.__index = Dog

-- Define with colon: self is implicit
function Dog:bark(times)
  for i = 1, (times or 1) do
    print(self.name .. ": Woof!")
  end
end

function Dog.new(name)
  return setmetatable({name=name}, Dog)
end

local d = Dog.new("Buddy")
d:bark(2)        -- Buddy: Woof! (x2)
-- Dog.bark(d,1) -- same thing, explicit self

Pola na poziomie klasy a pola na poziomie instancji

Pola w tabeli klasy są współdzielone przez wszystkie instancje (zmienne klasowe). Pola w tabeli instancji należą tylko do danej instancji. Instancja może przesłonić pole klasy, tworząc własne pole o tej samej nazwie.

local Entity = {}
Entity.__index = Entity
Entity.count = 0    -- class-level counter

function Entity.new(name)
  Entity.count = Entity.count + 1
  return setmetatable({name=name, id=Entity.count}, Entity)
end

local a = Entity.new("alpha")
local b = Entity.new("beta")
local c = Entity.new("gamma")

print(Entity.count)  -- 3
print(a.id, b.id, c.id)  -- 1  2  3

tostring dla klas

Dodaj __tostring do tabeli klasy, aby uzyskać czytelny wynik wypisywania. Ponieważ metatabelą instancji jest klasa, a klasa ma pole __tostring, wszystkie instancje będą używać go automatycznie.

local Vec2 = {}
Vec2.__index = Vec2
Vec2.__tostring = function(v)
  return string.format("Vec2(%g, %g)", v.x, v.y)
end

function Vec2.new(x,y)
  return setmetatable({x=x,y=y}, Vec2)
end

function Vec2.__add(a, b)
  return Vec2.new(a.x+b.x, a.y+b.y)
end

local v1 = Vec2.new(1,2)
local v2 = Vec2.new(3,4)
print(v1+v2)   -- Vec2(4, 6)

Sprawdzanie typu instancji

Można sprawdzić, czy obiekt jest instancją klasy, porównując jego metatabelę z tabelą klasy. Jest to odpowiednik instanceof w Lua.

local Dog = {}
Dog.__index = Dog

function Dog.new(name)
  return setmetatable({name=name}, Dog)
end

local function isDog(obj)
  return getmetatable(obj) == Dog
end

local d = Dog.new("Rex")
local t = {}
print(isDog(d))  -- true
print(isDog(t))  -- false

Metody prywatne

Metody prywatne są lokalnymi funkcjami w pliku modułu. Nie można ich wywoływać z zewnątrz, ale są dostępne wewnątrz publicznych metod modułu jako wartości upvalue.

local Account = {}
Account.__index = Account

-- Private helper
local function validate(amount)
  return type(amount)=="number" and amount > 0
end

function Account.new(balance)
  return setmetatable({balance=balance or 0}, Account)
end

function Account:deposit(amount)
  assert(validate(amount), "invalid amount")
  self.balance = self.balance + amount
end

function Account:getBalance() return self.balance end

Porównywanie klas

Przeciąż __eq i __lt, aby definiować własne reguły równości i porządku. Lua wywołuje __eq dla tabel tylko wtedy, gdy oba operandy mają tę samą metatabelę.

local Temp = {}
Temp.__index = Temp
Temp.__eq = function(a,b) return a.celsius == b.celsius end
Temp.__lt = function(a,b) return a.celsius < b.celsius end
Temp.__tostring = function(t)
  return t.celsius.."°C"
end

function Temp.new(c)
  return setmetatable({celsius=c}, Temp)
end

local t1 = Temp.new(100)
local t2 = Temp.new(0)
print(t1 == Temp.new(100))  -- true
print(t2 < t1)              -- true

Wiele klas

Każda klasa jest niezależną tabelą z własną metatabelą. Obiekty różnych klas mają różne metatabele. Stanowi to podstawę wieloklasowego systemu OOP w Lua.

local Cat = {}
Cat.__index = Cat

function Cat.new(name) return setmetatable({name=name,lives=9},Cat) end
function Cat:loseLife() self.lives=self.lives-1; return self.lives end

local Dog2 = {}
Dog2.__index = Dog2
function Dog2.new(name) return setmetatable({name=name,tricks={}},Dog2) end
function Dog2:learn(t) self.tricks[#self.tricks+1]=t end

local c = Cat.new("Whiskers")
local d = Dog2.new("Buddy")
d:learn("sit"); d:learn("stay")
print(c:loseLife(), #d.tricks)  -- 8  2

Szybkie sprawdzenie

Dlaczego ustawiamy ClassName.__index = ClassName?

Podsumowanie: klasy za pomocą metatabel

Podsumowanie:

  • Klasa = tabela + __index = self
  • Konstruktor: function Cls.new(...) return setmetatable({}, Cls) end
  • Metody: definiowane w tabeli klasy, wywoływane za pomocą składni z dwukropkiem
  • Pola klasy a pola instancji: pola klasy są współdzielone, a pola instancji należą do poszczególnych obiektów
  • Sprawdzanie typu: getmetatable(obj) == Cls

Często zadawane pytania

Czy lekcja „Klasy za pomocą metatabel” jest bezpłatna?

Tak — pełny tekst „Klasy za pomocą 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 „Klasy za pomocą metatabel”?

Proszę symulować klasy za pomocą tabel i __index do wyszukiwania metod. Ć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 „Klasy za pomocą 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

  1. Klasy za pomocą metatabel
  2. Konstruktory i new()
  3. Metody instancji i self
  4. Hermetyzacja za pomocą domknięć
← Powrót do Lua Academy