Tableaux métriques

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

Les métatables permettent aux tables de devenir plus puissantes qu'avant.Ils sont attachés aux données et contiennent des valeurs appelées métaméthodes.Les méthodes métamiques sont déclenchées lorsqu'une certaine action est utilisée avec le datum auquel elle est attachée.

Manipuler les métatables

Les deux fonctions principales pour ajouter et trouver un tableau mettable sont setmetatable() et getmetatable() .


local x = {}
local metaTable = {} -- Les tables metaTables sont aussi des tables !
setmetatable(x, metaTable) -- Donnez à x une table métatable appelée table meta !
print(getmetatable(x)) --> table: [hexadecimal memory address]

La fonction setmetatable() retourne également la table que vous définissez le métatable, donc ces deux scripts font la même chose :


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

local x = setmetatable({}, {})

Méthodes métamorphiques

Les métaméthodes sont les fonctions qui sont stockées à l'intérieur d'un métatable.Ils peuvent aller de l'appel d'une table à l'ajout d'une table, voire même diviser les tables également.Voici la liste des méthodes métamorphiques disponibles :

MéthodeAvertissement
__index(table, index)S'enflamme lorsque table[index] est indexé, si table[index] est nil. Peut également être défini sur une table, auquel cas cette table sera indexée.
__newindex(table, index, value)S'enflamme lorsque table[index] essaie d'être défini (table[index] = value), si table[index] est nil.Peut également être défini sur une table, auquel cas cette table sera indexée.
__call(table, ...)S'enflamme lorsque la table est appelée comme une fonction, ... sont les arguments qui ont été passés.
__concat(table, value)Se déclenche lorsque l'opérateur de concaténation .. est utilisé sur la table.
__unm(table)S'enflamme lorsque l'opérateur unaire est utilisé sur la table.
__add(table, value)L'opérateur d'ajout +.
__sub(table, value)L'opérateur de soustraction .
__mul(table, value)L'opérateur de multiplication *.
__div(table, value)L'opérateur de division /.
__idiv(table, value)L'opérateur de division de plancher //.
__mod(table, value)L'opérateur de modulateur %.
__pow(table, value)L'opérateur d'exposition ^.
__tostring(table)Tiré lorsque tostring est appelé sur la table.
__metatableSi présent, verrouille le metatable de sorte que getmetatable() retournera ceci au lieu du metatable et setmetatable() échouera. Valeur non fonctionnelle.
__eq(table, value)L'égalité de == à l'opérateur¹
__lt(table, value)L'opérateur inférieur à <
__le(table, value)L'opérateur <= ¹
__modeUtilisé dans les tables faibles, pour déclarer si les clés et/ou les valeurs d'une table sont faibles.Notez que les références aux instances Roblox ne sont jamais faibles.Les tables qui contiennent de telles références ne seront jamais collectées en tant que déchet.
__len(table)Tiré lorsque l'opérateur de longueur # est utilisé sur l'objet.
__iter(table)Utilisé pour indiquer un itérateur personnalisé lors de l'utilisation d'une itération généralisée.

Il est à noter que lors de l'écriture de fonctions pour les métaméthodes arithmétiques ou relationnelles, les deux paramètres de fonction sont interchangeables entre la table qui a déclenché la métaméthode et l'autre valeur.Par exemple, lorsque vous effectuez des opérations vectorielles avec une division de scalaires n'est pas commutative.Si vous écriviez des métaméthodes pour votre propre classe vector2, vous voudriez faire attention à tenir compte de l'un ou l'autre scénario.


local vector2 = {__type = "vector2"}
local mt = {__index = vector2}
function mt.__div(a, b)
if type(a) == "number" then
-- a est un scalar, b est un force vectorielle
local scalar, vector = a, b
return vector2.new(scalar / vector.x, scalar / vector.y)
elseif type(b) == "number" then
-- a est un force vectorielle, b est un scalar
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
-- à la fois a et b sont des vecteurs
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

Utilisation

Il existe de nombreuses façons d'utiliser les métatables, par exemple le métaméthode __unm pour rendre une table négative :


local metatable = {
__unm = function(t) -- __unm est pour l'opérateur unaire
local negated = {}
for key, value in t do
negated[key] = -value -- nier toutes les valeurs de cette table
end
return negated -- renvoie la table
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
print(table.concat(-table1, "; ")) --> -10; -11; -12

Voici une façon intéressante de déclarer des choses en utilisant __index :


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

__index a été tiré lorsque x a été indexé dans la table et n'a pas été trouvé.Luau a ensuite recherché dans la table __index pour un index appelé x, et, en en trouvant un, il l'a retourné.

Maintenant, vous pouvez facilement le faire avec une fonction simple, mais il y a beaucoup plus d'où cela vient. Prenez ceci pour exemple :


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

Typiquement, vous ne pouvez pas appeler une table, mais avec les métatables, vous pouvez :


local metatable = {
__call = function(t, param)
local sum = {}
for i, value in ipairs(t) do
sum[i] = value + param -- Ajoutez l'argument (5) à la valeur, puis placez-le dans la nouvelle table (t).
end
return unpack(sum) -- Retourner les valeurs de table individuelles
end
}
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35

Vous pouvez en faire beaucoup plus aussi, comme ajouter des tables :


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

Cela provoquera une erreur en disant que vous essayez d'effectuer une arithmétique sur une table, mais cela fonctionne lorsque vous l'essayez avec un métatable :


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

Lorsque vous jouez avec des métatables, vous pouvez rencontrer quelques problèmes.Si vous devez utiliser la méthode __index métaméthode pour créer de nouvelles valeurs dans une table, mais que la table métatable a également une méthode __newindex métaméthode, vous voudrez utiliser la fonction intégrée Luau rawset() pour définir la valeur sans invoquer aucune méthode métaméthode.Prenez le code suivant comme exemple de ce qui se produit si vous n'utilisez pas ces fonctions.


local t = setmetatable({}, {
__index = function(self, i)
self[i] = i * 10
return self[i]
end,
__newindex = function(self, i, v)
-- Ne définissez pas de valeurs à la table de la manière normale
end
})
print(t[1]) -- Causes a stack overflow

Les débordements de pile se produisent lorsque vous essayez d'appeler une fonction par elle-même trop de fois.Dans la fonction __index ci-dessus, self[i] est défini à une valeur, donc lorsqu'il arrive à la ligne suivante, self[i] devrait exister et ne devrait pas appeler la méthode métaméthode __index.Le problème est que __newindex ne vous laisse pas définir la valeur.Sa présence empêche les valeurs d'être ajoutées à la table avec la méthode standard t[i] = v.Pour contourner cela, utilisez la fonction rawset():


local t = setmetatable({}, {
__index = function(self, i)
rawset(self, i, i * 10)
return self[i]
end,
__newindex = function(self, i, v)
-- Ne définissez pas de valeurs à la table de la manière normale
end
})
print(t[1]) --> 10

Utiliser le type de données défini

Un ensemble est une collection d'éléments sans ordre et sans éléments en double.Un élément soit est ou n'est pas contenu dans un configurer.En utilisant des métatables, vous pouvez construire et manipuler des ensembles dans les scripts Luau.

Méthodes de base

Le code suivant inclut la fonctionnalité de jeu de base, vous permettant de construire de nouveaux ensembles, d'ajouter et de supprimer un item, de vérifier si un ensemble contient un itemet d'exporter le contenu d'un configurer.


local Set = {}
Set.__index = Set
-- Fonction de construction d'un ensemble à partir d'une liste facultative d'éléments
function Set.new(items)
local newSet = {}
for key, value in items or {} do
newSet[value] = true
end
return setmetatable(newSet, Set)
end
-- Fonction d'ajouter un élément à un configurer
function Set:add(item)
self[item] = true
end
-- Fonction pour supprimer un élément d'un configurer
function Set:remove(item)
self[item] = nil
end
-- Fonction pour vérifier si un ensemble contient un item
function Set:contains(item)
return self[item] == true
end
-- Fonction d'exportation définie comme une liste délimitée par des virgules pour le débogage
function Set:output()
local elems = {}
for key, value in self do
table.insert(elems, tostring(key))
end
print(table.concat(elems, ", "))
end

Créer un configurer

Un nouveau jeu peut être construit en appelant Set.new() avec un ensemble d'éléments optionnel à ajouter.


local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})

Notez que par définition, un ensemble n'a pas de concept d'ordre.

Ajouter un item

Ajouter un élément à un ensemble existant peut se faire via la méthode Set:add().


local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
fruits:add("Mango")

Supprimer l'item

Pour supprimer un élément d'un configurer, appelez Set:remove() avec le nom de l'élément.


local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
fruits:remove("Orange")

Vérifier l'item

Pour vérifier si un ensemble contient un itemspécifique, utilisez Set:contains() .


local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
local result1 = fruits:contains("Cherry")
print(result1) -- vrai
local result2 = fruits:contains("Watermelon")
print(result2) -- false

Méthodes supplémentaires

D'autres opérations utiles peuvent être mises en œuvre pour les ensembles, vous permettant de comparer des articles entre des ensembles, de combiner des ensembles ou de soustraire un ensemble à un autre.

Intersection

Lorsque vous envisagez les ensembles comme des diagrammes de Venn, vous pouvez obtenir l'intersection des deux ensembles comme suivant, ce qui signifie les éléments qui apparaissent dans les deux ensembles.


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", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
local frozenFruits = Set.new({"Mango", "Peach", "Pineapple"})
local commonFruits = getIntersection(freshFruits, frozenFruits)
commonFruits:output() -- Mango, Peach

Union

Vous pouvez obtenir l'union de deux ensembles avec la fonction suivante, ce qui signifie une collection des articles dans les deux ensembles sans duplicats.Notez que cette fonction utilise la méthode métatable __add pour fournir un raccourci supplémentaire de 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({"Apple", "Mango", "Cherry", "Peach"})
local sourFruits = Set.new({"Lemon", "Lime"})
local allFruits = sweetFruits + sourFruits
allFruits:output() -- Pêche, citron vert, pomme, cerise, citron, mangue

Sous-traitance

Vous pouvez supprimer tous les éléments d'un ensemble à partir des éléments d'un autre ensemble via la fonction suivante.Semblable à la fonction ci-dessus, cela utilise la méthode métatable __sub pour fournir un raccourci de soustraction de 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({"Apple", "Lemon", "Mango", "Cherry", "Lime", "Peach"})
local sourFruits = Set.new({"Lemon", "Lime"})
local sweetFruits = allFruits - sourFruits
sweetFruits:output() -- Mango, Apple, Cherry, Peach