0Pricing
Lua Academy · Lezione

Costruttori e new()

Scriva funzioni costruttrici che creino e inizializzino le istanze.

Costruttori e new() è una lezione Lua Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Lua Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Lua Academy include 4 lezioni in totale.

Responsabilità del costruttore

Un costruttore crea e inizializza un'istanza. Riceve i valori iniziali, li convalida, assegna valori predefiniti ai campi mancanti e restituisce la nuova istanza. Un costruttore ben progettato garantisce che ogni istanza inizi in uno stato valido.

local Player = {}
Player.__index = Player

function Player.new(name, hp, mp)
  assert(type(name)=="string" and name~="","need name")
  return setmetatable({
    name = name,
    hp   = hp or 100,
    mp   = mp or 50,
    alive = true,
    items = {},
  }, Player)
end

local p = Player.new("Hero")
print(p.name, p.hp, p.mp)  -- Hero  100  50

Costruttore fluente

Un costruttore fluente restituisce self dai metodi setter, consentendo di concatenare i metodi durante la costruzione. In Lua, questo è un builder pattern.

local Config = {}
Config.__index = Config

function Config.new()
  return setmetatable({_data={}}, Config)
end

function Config:set(k,v) self._data[k]=v; return self end
function Config:build() return self._data end

local cfg = Config.new()
  :set("host","localhost")
  :set("port",8080)
  :set("debug",true)
  :build()

print(cfg.host, cfg.port)

Costruttore di copia

Un costruttore di copia crea una nuova istanza con gli stessi valori di una già esistente. Importante: utilizzi una copia superficiale o profonda a seconda che le tabelle annidate debbano essere condivise o indipendenti.

local function deepCopy(orig)
  if type(orig)~="table" then return orig end
  local copy = {}
  for k,v in pairs(orig) do copy[deepCopy(k)]=deepCopy(v) end
  return setmetatable(copy, getmetatable(orig))
end

local Item = {}
Item.__index = Item

function Item.new(name, stats)
  return setmetatable({name=name, stats=stats or {}}, Item)
end

function Item:clone()
  return deepCopy(self)
end

local sword = Item.new("Sword",{damage=50})
local clone = sword:clone()
clone.stats.damage = 30
print(sword.stats.damage)  -- 50 (unchanged)

Costruttore con convalida

Convalidi sempre gli input del costruttore. Generi errori descrittivi per gli input non validi al livello 2 (responsabilità del chiamante). Questo consente di individuare rapidamente i bug e produce messaggi di errore utili.

local Rectangle = {}
Rectangle.__index = Rectangle

function Rectangle.new(w, h)
  assert(type(w)=="number" and w>0,"width must be positive number")
  assert(type(h)=="number" and h>0,"height must be positive number")
  return setmetatable({width=w, height=h}, Rectangle)
end

function Rectangle:area() return self.width * self.height end
function Rectangle:perimeter() return 2*(self.width+self.height) end

local r = Rectangle.new(5, 3)
print(r:area(), r:perimeter())  -- 15  16

Pattern dei valori predefiniti

Utilizzi una tabella dei valori predefiniti per gestire in modo ordinato i parametri opzionali del costruttore. In questo modo evita lunghe catene di x = x or default e rende i valori predefiniti espliciti e facili da modificare.

local Sprite = {}
Sprite.__index = Sprite

local DEFAULTS = {x=0,y=0,rotation=0,scale=1,visible=true,alpha=1}

function Sprite.new(image, opts)
  local cfg = opts or {}
  local self = {image=image}
  for k,v in pairs(DEFAULTS) do
    self[k] = cfg[k] ~= nil and cfg[k] or v
  end
  return setmetatable(self, Sprite)
end

local s = Sprite.new("hero.png",{x=100,y=200})
print(s.x,s.y,s.scale)  -- 100 200 1

Metodi factory statici

Una classe può avere diversi metodi factory per scenari di creazione differenti. È più ordinato che sovraccaricare un singolo costruttore con molti parametri opzionali.

local Color = {}
Color.__index = Color

function Color.fromRGB(r,g,b)
  return setmetatable({r=r,g=g,b=b}, Color)
end

function Color.fromHex(hex)
  hex = hex:gsub("#","")
  return setmetatable({
    r=tonumber(hex:sub(1,2),16),
    g=tonumber(hex:sub(3,4),16),
    b=tonumber(hex:sub(5,6),16),
  }, Color)
end

function Color:toHex()
  return string.format("#%02X%02X%02X",self.r,self.g,self.b)
end

local red = Color.fromHex("#FF0000")
print(red:toHex())  -- #FF0000

Registro dei costruttori

Utilizzi un registro per tenere traccia di tutte le istanze. Questo consente operazioni globali come "distruggi tutto" o l'iterazione su tutti gli oggetti di un tipo.

local Enemy = {}
Enemy.__index = Enemy
Enemy._all = {}

function Enemy.new(name, hp)
  local self = setmetatable({name=name, hp=hp}, Enemy)
  Enemy._all[#Enemy._all+1] = self
  return self
end

function Enemy.destroyAll()
  for _, e in ipairs(Enemy._all) do
    print("Destroying:", e.name)
  end
  Enemy._all = {}
end

Enemy.new("Goblin",30)
Enemy.new("Orc",80)
print("Count:", #Enemy._all)  -- 2
Enemy.destroyAll()

Inizializzazione lazy

Alcuni campi sono costosi da calcolare. Utilizzi __index con una funzione per calcolarli e memorizzarli nella cache al primo accesso.

local BigData = {}
BigData.__index = function(t, k)
  if k == "processed" then
    print("Computing processed...")
    local result = {}
    for i,v in ipairs(rawget(t,"raw")) do result[i]=v*2 end
    rawset(t,"processed",result)
    return result
  end
end

function BigData.new(raw)
  return setmetatable({raw=raw}, BigData)
end

local d = BigData.new({1,2,3,4,5})
print(d.processed[3])  -- Computing...  6
print(d.processed[3])  -- 6 (cached, no recompute)

Prototipo da un'istanza

Cloni un'istanza per crearne un'altra con gli stessi valori di base. Il clone ottiene la stessa metatabella (la stessa classe) e una copia dei dati dell'istanza. È utile per gli oggetti "modello".

local Unit = {}
Unit.__index = Unit

function Unit.new(t)
  return setmetatable({name=t.name,hp=t.hp,atk=t.atk}, Unit)
end

function Unit:clone()
  return Unit.new({name=self.name,hp=self.hp,atk=self.atk})
end

function Unit:__tostring()
  return self.name.."(HP:"..self.hp..",ATK:"..self.atk..")"
end

local template = Unit.new({name="Soldier",hp=100,atk=10})
local u1 = template:clone(); u1.name="Alpha"
local u2 = template:clone(); u2.name="Beta"
print(tostring(u1),tostring(u2))

Sicurezza dagli errori nel costruttore

Se la costruzione fallisce a metà (ad esempio durante l'allocazione di una risorsa), si assicuri che non sfuggano oggetti parzialmente creati. Utilizzi pcall per intercettare gli errori di costruzione e, se necessario, liberare le risorse.

local FileHandle = {}
FileHandle.__index = FileHandle

function FileHandle.new(path, mode)
  local f, err = io.open(path, mode or "r")
  if not f then
    return nil, "cannot open " .. path .. ": " .. err
  end
  return setmetatable({_f=f, path=path}, FileHandle)
end

function FileHandle:read(fmt) return self._f:read(fmt) end
function FileHandle:close() self._f:close() end

local fh, err = FileHandle.new("data.txt")
if not fh then print("Error:", err)
else print(fh:read("l")); fh:close()
end

Verifica rapida

Qual è il ruolo di un costruttore (new()) nella programmazione OOP in Lua?

Riepilogo: costruttori

Riepilogo:

  • Il costruttore convalida, inizializza e chiama setmetatable
  • Utilizzi una tabella dei valori predefiniti per gestire ordinatamente i parametri opzionali
  • Utilizzi più metodi factory per scenari di creazione differenti
  • Utilizzi un costruttore di clonazione per gli oggetti modello
  • Utilizzi l'inizializzazione lazy tramite __index per i campi costosi da calcolare
  • In caso di errore, il costruttore restituisce nil+err (allocazione di risorse)

Domande Frequenti

La lezione «Costruttori e new()» è gratuita?

Sì — il testo completo di «Costruttori e new()» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Lua Academy, passa a CoddyKit PRO. Il corso Lua Academy include 4 lezioni in totale.

Cosa imparerò in «Costruttori e new()»?

Scriva funzioni costruttrici che creino e inizializzino le istanze. Eserciti Lua Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Lua Academy?

Non è richiesta alcuna esperienza precedente. Lua Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Costruttori e new()»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Lua Academy?

Sì. Ogni lezione Lua Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Classi tramite metatabelle
  2. Costruttori e new()
  3. Metodi delle istanze e self
  4. Incapsulamento con le closure
← Torna a Lua Academy