Lua Academy · Lektion

Instansmetoder og self

Definér metoder med kolon-syntaks og den implicitte self-parameter.

Lektion 3 af 412 trin

Instansmetoder og self er en gratis Lua Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Lua Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Lua Academy-kurset indeholder 4 lektioner i alt.

self er instansen

Når du kalder obj:method(), sender Lua automatisk obj som det første argument. Efter konvention kaldes denne parameter self. Via self får metoden adgang til instansdata og kan kalde andre metoder.

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

Metodekæder

Returnér self fra metoder for at aktivere kædning: obj:method1():method2():method3(). Hvert kald returnerer det samme objekt, så du kan skrive i en flydende stil. Det fungerer bedst for metoder, der ændrer tilstanden.

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 OOP

Kald af andre metoder

Metoder kan kalde andre metoder på den samme instans via self:otherMethod(). Det fremmer genbrug af kode i en klasse. Private hjælpefunktioner kan være almindelige lokale funktioner, der modtager self eksplicit.

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  2

Advarsel om tilsidesættelse af metoder

Hvis du angiver et instansfelt med samme navn som en klassemetode, skjuler feltet metoden for den pågældende instans. Det er normalt en fejl — vær forsigtig, når navne på instansfelter kan kollidere med metoders navne.

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 value

self i callbacks

Når du sender en metode som callback, går det implicitte self tabt. Pak metoden ind i en closure for at indfange 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 times

Statiske metoder og instansmetoder

En statisk metode kaldes på klassen, ikke på en instans. Den har ingen self (eller modtager klassen som self). I Lua er der ingen formel forskel — efter konvention bruger du . (ikke :) til statiske metoder.

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)  -- 15

Mixin-metoder

Tilføj metoder fra en mixin-tabel til en klasse uden formel nedarvning. Det er flad komposition: Kopiér eller referér til mixinens funktioner i klassetabellen.

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())

Abstrakte metoder

Lua håndhæver ikke abstrakte metoder, men du kan definere en klassemetode i basisklassen, der udløser en fejl og tvinger underklasser til at tilsidesætte den. Det er en konvention for "skal tilsidesættes".

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: 16

Metodetabeller

For klasser med mange metoder kan du organisere dem i grupper efter funktionalitet. Alle metoder i den samme tabel bruger det samme opslag via metatabellen, men du kan opdele dem efter ansvarsområde ved hjælp af undernavnerum.

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)

Delegation kontra nedarvning

Foretræk delegation (at gemme en reference) frem for dybe nedarvningskæder. En klasse kan delegere til et andet objekt i stedet for at nedarve fra det, så koblingen forbliver løs, og hver klasse fokuserer på sit eget ansvar.

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()

Hurtigt tjek

Hvad er forskellen på obj:method() og obj.method()?

Opsummering: Instansmetoder

Opsummering:

  • Kolonkaldssyntaks: obj:method() == obj.method(obj)
  • Returnér self for at kæde metoder
  • Kald andre metoder: self:otherMethod()
  • Callbacks: Pak dem ind i en closure for at bevare self
  • Statiske metoder: Brug punktnotation efter konvention
  • Foretræk delegation frem for dyb nedarvning for større fleksibilitet
Gratis at komme i gang

Lær Lua med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
40
Lektioner
159

Ofte stillede spørgsmål

Er lektionen “Instansmetoder og self” gratis?

Ja — alle 3 lektioner i læringssporet Lua Academy, inklusive “Instansmetoder og self”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Lua Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Instansmetoder og self”?

Definér metoder med kolon-syntaks og den implicitte self-parameter. Du øver dig i Lua Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Lua Academy?

Der kræves ingen tidligere erfaring. Lua Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Instansmetoder og self”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Lua Academy-lektion?

Ja. Alle Lua Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Klasser via metatabeller
  2. Konstruktører og new()
  3. Instansmetoder og self
  4. Indkapsling med closures
← Tilbage til Lua Academy