Metatabelle

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Le metatabelle consentono alle tabelle di diventare più potenti di prima. Sono collegate ai dati e contengono valori chiamati metametodi. I metametodi vengono attivati quando si utilizza un'azione specifica con il dato a cui sono collegati.

Manipolare le metatabelle

Le due funzioni principali per aggiungere e trovare la metatabella di una tabella sono setmetatable() e getmetatable().


local x = {}
local metaTable = {} -- Le metatabelle sono anche tabelle!
setmetatable(x, metaTable) -- Assegna a x una metatabella chiamata metaTable!
print(getmetatable(x)) --> table: [indirizzo di memoria esadecimale]

La funzione setmetatable() restituisce anche la tabella di cui stai impostando la metatabella, quindi questi due script fanno la stessa cosa:


local x = {}
setmetatable(x, {})

local x = setmetatable({}, {})

Metametodi

I metametodi sono le funzioni che sono memorizzate all'interno di una metatabella. Possono variare dall'invocare una tabella, all'aggiungere una tabella, fino a dividere le tabelle. Ecco l'elenco dei metametodi disponibili:

MetodoDescrizione
__index(table, index)Viene attivato quando table[index] viene indicizzato, se table[index] è nil. Può anche essere impostato su una tabella, nel qual caso quella tabella verrà indicizzata.
__newindex(table, index, value)Viene attivato quando si cerca di impostare table[index] (table[index] = value), se table[index] è nil. Può anche essere impostato su una tabella, nel qual caso quella tabella verrà indicizzata.
__call(table, ...)Viene attivato quando la tabella viene chiamata come una funzione, ... sono gli argomenti che sono stati passati.
__concat(table, value)Viene attivato quando viene utilizzato l'operatore di concatenazione .. sulla tabella.
__unm(table)Viene attivato quando l'operatore unario viene utilizzato sulla tabella.
__add(table, value)L'operatore di somma +.
__sub(table, value)L'operatore di sottrazione .
__mul(table, value)L'operatore di moltiplicazione *.
__div(table, value)L'operatore di divisione /.
__idiv(table, value)L'operatore di divisione intera //.
__mod(table, value)L'operatore di modulo %.
__pow(table, value)L'operatore di esponenziazione ^.
__tostring(table)Attivato quando viene chiamato tostring sulla tabella.
__metatableSe presente, blocca la metatabella in modo che getmetatable() restituisca questa al posto della metatabella e setmetatable() generi un errore. Valore non funzione.
__eq(table, value)L'operatore di uguaglianza ==¹
__lt(table, value)L'operatore di minore <¹
__le(table, value)L'operatore di minore o uguale <=¹
__modeUtilizzato nelle tabelle deboli, dichiarando se le chiavi e/o i valori di una tabella sono deboli. Nota che i riferimenti alle istanze di Roblox non sono mai deboli. Le tabelle che contengono tali riferimenti non verranno mai raccolte da garbage collection.
__len(table)Attivato quando viene utilizzato l'operatore di lunghezza # sull'oggetto.
__iter(table)Utilizzato per denotare un iteratore personalizzato quando si utilizza l'iterazione generalizzata.

Va notato che quando si scrivono funzioni per i metametodi aritmetici o relazionali, i due parametri della funzione sono intercambiabili tra la tabella che ha attivato il metametodo e l'altro valore. Ad esempio, durante le operazioni vettoriali con scalari, la divisione non è commutativa. Pertanto, se stessi scrivendo metametodi per la tua classe vector2, dovresti fare attenzione a tenere conto di entrambi gli scenari.


local vector2 = {__type = "vector2"}
local mt = {__index = vector2}
function mt.__div(a, b)
if type(a) == "number" then
-- a è uno scalare, b è un vettore
local scalar, vector = a, b
return vector2.new(scalar / vector.x, scalar / vector.y)
elseif type(b) == "number" then
-- a è un vettore, b è uno scalare
local vector, scalar = a, b
return vector2.new(vector.x / scalar, vector.y / scalar)
elseif (a.__type and a.__type == "vector2" and b.__type and b.__type == "vector2") then
-- sia a che b sono vettori
return vector2.new(a.x / b.x, a.y / b.y)
end
end
function mt.__tostring(t)
return t.x .. ", " .. t.y
end
function vector2.new(x, y)
local self = setmetatable({}, mt)
self.x = x or 0
self.y = y or 0
return self
end
local a = vector2.new(10, 5)
local b = vector2.new(-3, 4)
print(a / b) -- -3.3333333333333, 1.25
print(b / a) -- -0.3, 0.8
print(2 / a) -- 0.2, 0.4
print(a / 2) -- 5, 2.5

Utilizzo

Ci sono molti modi per usare le metatabelle, ad esempio il metametodo __unm per rendere negativa una tabella:


local metatable = {
__unm = function(t) -- __unm è per l'operatore unario -
local negated = {}
for key, value in t do
negated[key] = -value -- nega tutti i valori in questa tabella
end
return negated -- restituisce la tabella
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
print(table.concat(-table1, "; ")) --> -10; -11; -12

Ecco un modo interessante per dichiarare cose utilizzando __index:


local metatable = {
__index = {x = 1}
}
local t = setmetatable({}, metatable)
print(t.x) --> 1

__index è stato attivato quando x è stato indicizzato nella tabella e non trovato. Luau ha quindi cercato attraverso la tabella __index per un indice chiamato x, e, trovandone uno, lo ha restituito.

Ora puoi facilmente fare ciò con una funzione semplice, ma c'è molto di più. Prendi ad esempio questo:


local t = {10, 20, 30}
print(t(5))

Tipicamente non puoi chiamare una tabella, ma con le metatabelle puoi farlo:


local metatable = {
__call = function(t, param)
local sum = {}
for i, value in ipairs(t) do
sum[i] = value + param -- Aggiunge l'argomento (5) al valore, poi lo piazza nella nuova tabella (t).
end
return unpack(sum) -- Restituisce i singoli valori della tabella
end
}
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35

Puoi fare molto di più, come aggiungere tabelle:


local table1 = {10, 11, 12}
local table2 = {13, 14, 15}
for k, v in table1 + table2 do
print(k, v)
end

Questo genererà un errore dicendo che stai tentando di eseguire operazioni aritmetiche su una tabella, ma funziona se provato con una metatabella:


local metatable = {
__add = function(t1, t2)
local sum = {}
for key, value in t1 do
sum[key] = value
end
for key, value in t2 do
if sum[key] then
sum[key] += value
else
sum[key] = value
end
end
return sum
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
local table2 = setmetatable({13, 14, 15}, metatable)
for k, v in table1 + table2 do
print(k, v)
end

Quando giochi con le metatabelle, potresti incontrare alcuni problemi. Se hai bisogno di utilizzare il metametodo __index per creare nuovi valori in una tabella, ma la metatabella di quella tabella ha anche un metametodo __newindex, dovrai utilizzare la funzione integrata di Luau rawset() per impostare il valore senza attivare alcun metametodo. Prendi il seguente codice come esempio di ciò che succede se non utilizzi queste funzioni.


local t = setmetatable({}, {
__index = function(self, i)
self[i] = i * 10
return self[i]
end,
__newindex = function(self, i, v)
-- Non impostare valori nella tabella nel modo normale
end
})
print(t[1]) -- Causa un overflow dello stack

Gli overflow dello stack si verificano quando cerchi di chiamare una funzione da se stessa troppe volte. Nella funzione __index sopra, self[i] viene impostato a un valore, quindi quando si arriva alla riga successiva, self[i] dovrebbe esistere e presumibilmente non attiverà il metametodo __index. Il problema è che __newindex non ti consente di impostare il valore. La sua presenza impedisce di aggiungere valori alla tabella con il metodo standard t[i] = v. Per superare questo, utilizza la funzione rawset():


local t = setmetatable({}, {
__index = function(self, i)
rawset(self, i, i * 10)
return self[i]
end,
__newindex = function(self, i, v)
-- Non impostare valori nella tabella nel modo normale
end
})
print(t[1]) --> 10

Usa il tipo di dato set

Un set è una collezione di elementi senza ordine e senza elementi duplicati. Un elemento è o non è contenuto in un set. Utilizzando le metatabelle, puoi costruire e manipolare set all'interno degli script Luau.

Metodi di base

Il seguente codice include la funzionalità di base del set, consentendo di costruire nuovi set, aggiungere e rimuovere un elemento, controllare se un set contiene un elemento e visualizzare il contenuto di un set.


local Set = {}
Set.__index = Set
-- Funzione per costruire un set da un elenco opzionale di elementi
function Set.new(items)
local newSet = {}
for key, value in items or {} do
newSet[value] = true
end
return setmetatable(newSet, Set)
end
-- Funzione per aggiungere un elemento a un set
function Set:add(item)
self[item] = true
end
-- Funzione per rimuovere un elemento da un set
function Set:remove(item)
self[item] = nil
end
-- Funzione per controllare se un set contiene un elemento
function Set:contains(item)
return self[item] == true
end
-- Funzione per visualizzare il set come un elenco delimitato da virgole per il debug
function Set:output()
local elems = {}
for key, value in self do
table.insert(elems, tostring(key))
end
print(table.concat(elems, ", "))
end

Crea set

Un nuovo set può essere costruito chiamando Set.new() con un array opzionale di elementi da aggiungere.


local fruits = Set.new({"Mela", "Limone", "Arancia", "Ciliegia", "Lime", "Pesca"})

Nota che per definizione, un set non ha concetto di ordinamento.

Aggiungi elemento

Aggiungere un elemento a un set esistente può essere fatto tramite il metodo Set:add().


local fruits = Set.new({"Mela", "Limone", "Arancia", "Ciliegia", "Lime", "Pesca"})
fruits:add("Mango")

Rimuovi elemento

Per rimuovere un elemento da un set, chiama Set:remove() con il nome dell'elemento.


local fruits = Set.new({"Mela", "Limone", "Arancia", "Ciliegia", "Lime", "Pesca"})
fruits:remove("Arancia")

Controlla presenza di elemento

Per controllare se un set contiene un elemento specifico, usa Set:contains().


local fruits = Set.new({"Mela", "Limone", "Arancia", "Ciliegia", "Lime", "Pesca"})
local result1 = fruits:contains("Ciliegia")
print(result1) -- true
local result2 = fruits:contains("Anguria")
print(result2) -- false

Metodi aggiuntivi

Altre operazioni utili possono essere implementate per i set, consentendo di confrontare elementi tra i set, combinare set o sottrarre un set da un altro.

Intersezione

Quando si considerano i set come diagrammi di Venn, puoi ottenere l'intersezione di due set come segue, significando gli elementi che appaiono in entrambi i set.


local function getIntersection(set1, set2)
local result = Set.new()
for key, value in set1 do
if set2:contains(key) then
result:add(key)
end
end
return result
end
local freshFruits = Set.new({"Mango", "Limone", "Arancia", "Ciliegia", "Lime", "Pesca"})
local frozenFruits = Set.new({"Mango", "Pesca", "Ananas"})
local commonFruits = getIntersection(freshFruits, frozenFruits)
commonFruits:output() -- Mango, Pesca

Unione

Puoi ottenere l'unione di due set con la seguente funzione, significando una collezione degli elementi in entrambi i set senza duplicati. Nota che questa funzione utilizza il metodo __add della metatabella per fornire un'abbreviazione di aggiunta di set1 + set2.


function Set:__add(otherSet)
local result = Set.new()
for entry in self do
result[entry] = true
end
for entry in otherSet do
result[entry] = true
end
return result
end
local sweetFruits = Set.new({"Mela", "Mango", "Ciliegia", "Pesca"})
local sourFruits = Set.new({"Limone", "Lime"})
local allFruits = sweetFruits + sourFruits
allFruits:output() -- Pesca, Lime, Mela, Ciliegia, Limone, Mango

Sottrazione

Puoi rimuovere tutti gli elementi in un set dagli elementi in un altro set tramite la seguente funzione. Simile alla funzione sopra, questa utilizza il metodo __sub della metatabella per fornire un'abbreviazione di sottrazione di set1 - set2.


function Set:__sub(otherSet)
local result = Set.new()
for entry in self do
result[entry] = true
end
for entry in otherSet do
result[entry] = nil
end
return result
end
local allFruits = Set.new({"Mela", "Limone", "Mango", "Ciliegia", "Lime", "Pesca"})
local sourFruits = Set.new({"Limone", "Lime"})
local sweetFruits = allFruits - sourFruits
sweetFruits:output() -- Mango, Mela, Ciliegia, Pesca
© 2026 Roblox Corporation. Roblox, il logo Roblox e Powering Imagination sono tra i nostri marchi registrati e non registrati negli Stati Uniti. e altri paesi.