Lua Academy · Lektion

Klasser via metatabeller

Simulér klasser ved hjælp af tabeller og __index til opslag af metoder.

Lektion 1 af 412 trin

Klasser via metatabeller er en gratis Lua Academy-lektion på CoddyKit. Dette er lektion 1 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.

Mønsteret med klassetabeller

I Lua er en »klasse« blot en tabel, der gemmer metoder. Instanser er tabeller, hvis metatabels __index peger på klassetabellen. Det gør alle metoder tilgængelige på instanser via opslag i kæden.

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 peger på klassen

Hvis du indstiller ClassName.__index = ClassName, betyder det »slå manglende nøgler op i klassetabellen«. Når en instansmetode kaldes, finder Lua den ikke i instansen, kontrollerer metatabellen (__index), finder klassen og slår metoden op dér.

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)

Konstruktørmønster

Funktionen new() er konstruktøren: Den opretter en tabel med instansdata og returnerer den pakket ind i en metatabel, der peger på klassen. Dette er standardmåden at oprette objekter på i 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()))

Metode- kontra funktionssyntaks

obj:method() er syntaktisk sukker for obj.method(obj). Definér metoder med kolon-syntaks (function Cls:method()) for at få et implicit self. Kald dem med kolon for at overføre instansen. Hvis du blander punktum og kolon, opstår der subtile fejl.

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

Felter på klasse- og instansniveau

Felter i klassetabellen deles af alle instanser (klassevariabler). Felter i instanstabellen er specifikke for hver instans. En instans kan skjule et klassefelt ved at oprette sit eget felt med samme navn.

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 til klasser

Føj __tostring til klassetabellen for at få læsbare udskrifter. Da instansens metatabel er klassen, og klassen har __tostring, bruger alle instanser det automatisk.

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)

Kontrol af instanstype

Kontrollér, om et objekt er en instans af en klasse, ved at sammenligne dets metatabel med klassetabellen. Dette er Lua's pendant til instanceof.

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

Private metoder

Private metoder er lokale funktioner i modulfilen. De kan ikke kaldes udefra, men er tilgængelige i modulets offentlige metoder som upvalues.

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

Sammenligning af klasser

Overbelast __eq og __lt for brugerdefineret lighed og sortering. Lua kalder kun __eq for tabeller, når begge operander deler den samme 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

Flere klasser

Hver klasse er en uafhængig tabel med sin egen metatabel. Objekter fra forskellige klasser har forskellige metatabeller. Dette er grundlaget for et objektorienteret system med flere klasser i 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

Hurtigt tjek

Hvorfor indstiller vi ClassName.__index = ClassName?

Opsummering: Klasser via metatabeller

Opsummering:

  • Klasse = tabel + __index = self
  • Konstruktør: function Cls.new(...) return setmetatable({}, Cls) end
  • Metoder: defineres i klassetabellen og kaldes med kolon-syntaks
  • Klasse- kontra instansfelter: klassefelter deles, instansfelter er specifikke for hvert objekt
  • Typekontrol: getmetatable(obj) == Cls
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 “Klasser via metatabeller” gratis?

Ja — alle 3 lektioner i læringssporet Lua Academy, inklusive “Klasser via metatabeller”, 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 “Klasser via metatabeller”?

Simulér klasser ved hjælp af tabeller og __index til opslag af metoder. 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 1 af 4.

Hvor lang tid tager lektionen “Klasser via metatabeller”?

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