Metody instancji i self
Proszę definiować metody za pomocą składni dwukropka i niejawnego parametru self.
Metody instancji i self 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.
self to instancja
Gdy wywołuje Pan/Pani obj:method(), Lua automatycznie przekazuje obj jako pierwszy argument. Zgodnie z konwencją ten parametr nosi nazwę self. Za pośrednictwem self metoda uzyskuje dostęp do danych instancji i wywołuje inne metody.
local Counter = {}
Counter.__index = Counter
function Counter.new(start)
return setmetatable({value=start or 0, step=1}, Counter)
end
function Counter:increment()
self.value = self.value + self.step
end
function Counter:getValue() return self.value end
local c = Counter.new(10)
c:increment(); c:increment()
print(c:getValue()) -- 12Łańcuchowe wywoływanie metod
Należy zwracać self z metod, aby umożliwić łańcuchowe wywoływanie: obj:method1():method2():method3(). Każde wywołanie zwraca ten sam obiekt, umożliwiając płynny styl programowania. Najlepiej sprawdza się to w przypadku metod modyfikujących stan.
local Builder = {}
Builder.__index = Builder
function Builder.new()
return setmetatable({parts={}},Builder)
end
function Builder:add(s) self.parts[#self.parts+1]=s; return self end
function Builder:addAll(t)
for _,v in ipairs(t) do self.parts[#self.parts+1]=v end
return self
end
function Builder:build() return table.concat(self.parts," ") end
local result = Builder.new()
:add("Hello")
:add("from")
:addAll({"Lua","OOP"})
:build()
print(result) -- Hello from Lua OOPWywoływanie innych metod
Metody mogą wywoływać inne metody tej samej instancji za pomocą self:otherMethod(). Sprzyja to ponownemu wykorzystaniu kodu w obrębie klasy. Prywatne funkcje pomocnicze mogą być zwykłymi funkcjami lokalnymi, które jawnie otrzymują self.
local Stack = {}
Stack.__index = Stack
function Stack.new() return setmetatable({_data={},_size=0},Stack) end
function Stack:push(v) self._size=self._size+1; self._data[self._size]=v end
function Stack:pop()
if self:isEmpty() then return nil end
local v=self._data[self._size]; self._data[self._size]=nil
self._size=self._size-1; return v
end
function Stack:peek()
return not self:isEmpty() and self._data[self._size] or nil
end
function Stack:isEmpty() return self._size==0 end
function Stack:size() return self._size end
local s=Stack.new(); s:push(1);s:push(2);s:push(3)
print(s:pop(),s:peek(),s:size()) -- 3 2 2Ostrzeżenie dotyczące przesłaniania metod
Ustawienie pola instancji o takiej samej nazwie jak metoda klasy przesłania tę metodę dla danej instancji. Zwykle jest to błąd — należy zachować ostrożność, gdy nazwy pól instancji mogą kolidować z nazwami metod.
local Dog = {}
Dog.__index = Dog
function Dog.new(n) return setmetatable({name=n},Dog) end
function Dog:speak() print(self.name..": Woof!") end
local d = Dog.new("Rex")
d:speak() -- Rex: Woof!
-- Accidental shadow:
d.speak = "loud" -- now d.speak is a string, not a function
local ok,err = pcall(function() d:speak() end)
print(ok, err) -- false attempt to call a string valueself w callbackach
Przekazanie metody jako callbacku powoduje utratę niejawnego self. Należy opakować metodę w domknięcie, aby przechwycić self.
local Timer = {}
Timer.__index = Timer
function Timer.new(n) return setmetatable({count=n},Timer) end
function Timer:tick()
self.count=self.count-1
print("Ticking, count:", self.count)
end
local t = Timer.new(3)
-- Wrong: loses self
-- local cb = t.tick -- cb(t) works but cb() doesn't
-- Correct: closure captures self
local cb = function() t:tick() end
cb(); cb(); cb() -- Ticking 3 timesMetody statyczne a metody instancji
Metodę statyczną wywołuje się na klasie, a nie na instancji. Nie ma ona self (lub otrzymuje klasę jako self). W Lua nie ma formalnego rozróżnienia — zgodnie z konwencją dla metod statycznych należy używać ., a nie :.
local MathUtils = {}
MathUtils.__index = MathUtils
-- Static method (no instance needed)
function MathUtils.clamp(v, lo, hi)
return math.max(lo, math.min(hi, v))
end
-- Instance method (needs self)
function MathUtils:scale(factor)
self.value = self.value * factor
end
print(MathUtils.clamp(15, 0, 10)) -- 10
local m = setmetatable({value=5},MathUtils)
m:scale(3)
print(m.value) -- 15Metody mixinów
Należy dodać metody z tabeli mixinu do klasy bez formalnego dziedziczenia. Jest to kompozycja płaska: funkcje mixinu są kopiowane do tabeli klasy lub udostępniane przez odwołanie.
local Serializable = {}
function Serializable:serialize()
local parts={}
for k,v in pairs(self) do
if type(v)~="function" then
parts[#parts+1]=k.."="..tostring(v)
end
end
return "{"..table.concat(parts,",").."}"
end
local User = {}
User.__index = User
User.serialize = Serializable.serialize -- mixin!
function User.new(n,a) return setmetatable({name=n,age=a},User) end
local u = User.new("Alice",30)
print(u:serialize())Metody abstrakcyjne
Lua nie wymusza stosowania metod abstrakcyjnych, ale można zdefiniować metodę klasy bazowej, która zgłasza błąd, zmuszając klasy pochodne do jej przesłonięcia. Jest to konwencja oznaczająca „musi zostać przesłonięta”.
local Shape = {}
Shape.__index = Shape
function Shape.new() return setmetatable({},Shape) end
function Shape:area()
error(type(self).." must implement area()",2)
end
function Shape:describe()
print("Shape area:", self:area())
end
local sq={}
setmetatable(sq,{__index=Shape})
function sq:area() return 4*4 end
sq:describe() -- Shape area: 16Tabele metod
W klasach zawierających wiele metod należy organizować je w grupy według funkcjonalności. Wszystkie metody w tej samej tabeli korzystają z tego samego wyszukiwania przez metatabelę, ale można podzielić je według odpowiedzialności za pomocą podprzestrzeni nazw.
local Entity = {}
Entity.__index = Entity
Entity.Physics = {}
function Entity.Physics:applyForce(fx,fy)
self.vx=(self.vx or 0)+fx
self.vy=(self.vy or 0)+fy
end
Entity.Render = {}
function Entity.Render:draw()
print(string.format("Draw at (%g,%g)",self.x or 0,self.y or 0))
end
-- Mix into main class
for k,v in pairs(Entity.Physics) do Entity[k]=v end
for k,v in pairs(Entity.Render) do Entity[k]=v end
function Entity.new(x,y) return setmetatable({x=x,y=y},Entity) end
local e=Entity.new(10,20); e:draw(); e:applyForce(5,0); print(e.vx)Delegowanie a dziedziczenie
Należy preferować delegowanie (przechowywanie odwołania) zamiast głębokich łańcuchów dziedziczenia. Klasa może delegować zadania innemu obiektowi, zamiast po nim dziedziczyć, dzięki czemu sprzężenie pozostaje niewielkie, a każda klasa zachowuje jasno określoną odpowiedzialność.
local Logger = {}
Logger.__index = Logger
function Logger.new(name) return setmetatable({name=name},Logger) end
function Logger:log(msg) print("["..self.name.."] "..msg) end
local Service = {}
Service.__index = Service
function Service.new(name)
return setmetatable({
name=name,
logger=Logger.new(name) -- delegation
},Service)
end
function Service:start()
self.logger:log("starting...") -- delegate logging
print(self.name, "running")
end
Service.new("AuthService"):start()Szybkie sprawdzenie
Czym różnią się obj:method() i obj.method()?
Podsumowanie: metody instancji
Podsumowanie:
- Składnia wywołania z dwukropkiem:
obj:method()==obj.method(obj) - Należy zwracać self, aby umożliwić łańcuchowe wywoływanie metod
- Inne metody należy wywoływać za pomocą
self:otherMethod() - Callbacki należy opakowywać w domknięcie, aby zachować self
- Metody statyczne należy zgodnie z konwencją wywoływać za pomocą notacji kropkowej
- Dla większej elastyczności należy preferować delegowanie zamiast głębokiego dziedziczenia
Często zadawane pytania
Czy lekcja „Metody instancji i self” jest bezpłatna?
Tak — pełny tekst „Metody instancji i self” 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 „Metody instancji i self”?
Proszę definiować metody za pomocą składni dwukropka i niejawnego parametru self. Ć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 „Metody instancji i self”?
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
- Klasy za pomocą metatabel
- Konstruktory i new()
- Metody instancji i self
- Hermetyzacja za pomocą domknięć