Met tabloları

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

Metatablolar, tabloların daha öncekinden daha güçlü hale gelmesine izin verir.Verilere bağlıdırlar ve metodlar olarak adlandırılan değerler içerirler.Metodlar, belli bir eylem belirli bir veriye bağlandığında kullanıldığında ateşlenir.

Metatabloları manipüle et

Bir tablonun metatable eklenmesi ve bulunması için iki temel işlev setmetatable() ve getmetatable() dir.


local x = {}
local metaTable = {} -- metaTablolar da masalardır!
setmetatable(x, metaTable) -- x'e metaTablo adlı bir masa ver!
print(getmetatable(x)) --> table: [hexadecimal memory address]

setmetatable() fonksiyonu da ayarladığınız tabloyu geri verir, bu yüzden bu iki kod aynı şeyi yapar:


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

local x = setmetatable({}, {})

Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları Metodları

Metodlar, bir metatable içinde saklanan işlevlerdir.Bir tabloyu çağırmaktan, bir tablo eklemekten, hatta tabloları bölmekten bile geçebilirler.Burada mevcut metodların listesi:

MetoduAçıklama
__index(table, index)table[index] indekslenirken yanar, eğer table[index] ise nil . Ayrıca bir tabloya ayarlanabilir, bu durumda o tablo indekslenecektir.
__newindex(table, index, value)table[index] ayarlanmaya çalışırken (table[index] = value) ateş eder, eğer table[index] ise nil .Ayrıca bir tabloya ayarlanabilir, bu durumda tablo indekslenecektir.
__call(table, ...)Tablo bir işlev gibi çağrıldığında ateş eder, ... geçilen argümanlarıdır.
__concat(table, value)Masada .. bağlantı işleci kullanıldığında ateş eder.
__unm(table)Masada birincil operatörü kullanıldığında ateş eder.
__add(table, value)The + eklem operatörü.
__sub(table, value) çıkarma işleci.
__mul(table, value)The * çarpan işleci.
__div(table, value)The / bölüm operatörü.
__idiv(table, value)// zemin bölüm operatörü.
__mod(table, value)The % modül operatörü.
__pow(table, value)The ^ çarpan işlev operatörü.
__tostring(table)table'de tostring çağrıldığında ateş edilir.
__metatableMevcutsa, metatable'i kilitler, böylece getmetatable() bunun yerine metatable'i döndürür ve setmetatable() hata verir. İşlevsiz değer.
__eq(table, value)Operatörüne eşit olan == operatörü¹
__lt(table, value)Operatörden < daha az olan ¹
__le(table, value)The <= operatörü¹
__modeZayıf tablolarda kullanılır ve bir tablonun anahtarlarının ve/veya değerlerinin zayıf olup olmadığını belirler.Roblox örneklerine yönelik referanslar asla zayıf olmaz.Bu referansları tutan tablolar asla çöp toplanmayacaktır.
__len(table)Nesneye # uzunluk işleci kullanıldığında ateş edilir.
__iter(table)Genelleştirilmiş döngü kullanırken özel bir döngü belirtmek için kullanılır.

Aritmetik veya ilişkisel metodlar için işlevler yazılırken, iki işlev parametri metodun ateşlendiği tablo ve diğer değer arasında değiştirilebilir olmalıdır.Örneğin, skalar bölümü ile vektör operasyonları yaparken komutatif değildir.Bu nedenle, kendi vector2 sınıfınız için metodlar yazıyorsanız, her iki senaryoyu da hesaba katmak için dikkatli olmak istersiniz.


local vector2 = {__type = "vector2"}
local mt = {__index = vector2}
function mt.__div(a, b)
if type(a) == "number" then
-- a bir skalardır, b bir vektördür
local scalar, vector = a, b
return vector2.new(scalar / vector.x, scalar / vector.y)
elseif type(b) == "number" then
-- a bir vektör, b bir skalardır
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
-- her ikisi de vektörlerdir
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

Kullanım

Metatabloları kullanmanın birçok yolu vardır, örneğin bir tabloyu negatif hale getirmek için __unm metodu:


local metatable = {
__unm = function(t) -- __unm birincil - operatörü içindir
local negated = {}
for key, value in t do
negated[key] = -value -- bu tablodaki tüm değerleri reddet
end
return negated -- masayı geri ver
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
print(table.concat(-table1, "; ")) --> -10; -11; -12

İşleri __index kullanarak ilan etmenin ilginç bir yolu:


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

__index tabloda indekslendiğinde ve bulunmadığında x indekslenmişti ve ateşlendi.Luau ardından __index tablosunda bir indeks olan x için aradı ve bir tane bulduğunda bunu geri döndürdü.

Artık basit bir işlevle bunu kolayca yapabilirsiniz, ancak bunun geldiği yer çok daha fazla var. Örneğin şunu alın:


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

Genellikle bir tablo çağıramazsınız, ancak metatablolarla şunları yapabilirsiniz:


local metatable = {
__call = function(t, param)
local sum = {}
for i, value in ipairs(t) do
sum[i] = value + param -- Değere (5) argümanı ekleyin, ardından yeni tabloya yerleştirin (t).
end
return unpack(sum) -- Tek tablo değerlerini geri dönün
end
}
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35

Ayrıca tablolar eklemek gibi daha fazla şey yapabilirsiniz:


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

Bu, bir tablo üzerinde aritmetik yapmaya çalıştığınızı söyleyen bir hata olacak, ancak bir metatable ile denendiğinde çalışıyor:


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

Metatablolarla oynarken, bazı sorunlarla karşılaşabilirsiniz.Bir tabloda yeni değerler oluşturmak için __index metodunu kullanmanız gerekiyorsa, ancak bu tablonun metatablosu da bir __newindex metodu içeriyorsa, herhangi bir metod çağırmadan Luau yerleşik işlevini rawset() kullanarak değeri ayarlamak istersiniz.Bu işlevleri kullanmazsanız ne olacağına dair bir örnek olarak aşağıdaki kodu alın.


local t = setmetatable({}, {
__index = function(self, i)
self[i] = i * 10
return self[i]
end,
__newindex = function(self, i, v)
-- Değerleri normal yoldan masaya ayarlamayın
end
})
print(t[1]) -- Causes a stack overflow

Yığınır aşırı yüklenmeler, bir işlevi kendisinden çok kez çağırmaya çalıştığınızda meydana gelir.Yukarıdaki __index işlevinde, self[i] bir değere ayarlanır, bu nedenle bir sonraki satıra ulaştığında, self[i] var olmalı ve muhtemelen __index metodunu çağırmayacaktır.Sorun şu ki __newindex değeri ayarlamanıza izin vermiyor.Varlığı, değerlerin standart t[i] = v yöntemiyle tabloya eklenmesini durdurur.Bunun üstesinden gelmek için, rawset() fonksiyonunu kullanın:


local t = setmetatable({}, {
__index = function(self, i)
rawset(self, i, i * 10)
return self[i]
end,
__newindex = function(self, i, v)
-- Değerleri normal yoldan masaya ayarlamayın
end
})
print(t[1]) --> 10

Ayarılmış veri türünü kullan

Bir set hiçbir sıralama ve yinelenen öğe olmayan bir koleksiyon öğeleridir.Bir öğe ya içinde bulunur ya da içinde bulunmaz bir ayarlaiçinde.Metatabloları kullanarak, Luau betikleri içinde setler oluşturabilir ve manipüle edebilirsiniz.

Temel yöntemler

Aşağıdaki kod temel set işlevlerini içerir, yeni setler oluşturmanıza, bir öğe eklenmesine veya kaldırılmasına izin verir, bir setin içeriğini kontrol eder ve bir ayarlaiçeriğini çıkarır.


local Set = {}
Set.__index = Set
-- Opsiyonel bir öğe listesinden bir dizi oluşturmak için işlev
function Set.new(items)
local newSet = {}
for key, value in items or {} do
newSet[value] = true
end
return setmetatable(newSet, Set)
end
-- Bir öğeyi bir ayarlaekleyen işlev
function Set:add(item)
self[item] = true
end
-- Bir öğeyi bir ayarlakaldırmak için işlev
function Set:remove(item)
self[item] = nil
end
-- Bir düzenin bir öğe içerip içermediğini kontrol etmek için işlev
function Set:contains(item)
return self[item] == true
end
-- Sorun giderme için virgülle ayrılmış bir liste olarak dışa aktarma işlevi
function Set:output()
local elems = {}
for key, value in self do
table.insert(elems, tostring(key))
end
print(table.concat(elems, ", "))
end

ayarlaoluştur

Yeni bir set, eklemek için isteğe bağlı bir dizi ile Set.new() 'yi arayarak oluşturulabilir.


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

Tanıma göre, bir setin sıralama konsepti yoktur.

Eşya öğe

Mevcut bir sete bir öğe eklemek Set:add() yöntemi aracılığıyla yapılabilir.


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

öğekaldır

Bir öğeyi bir ayarlakaldırmak için, öğe adıyla Set:remove() arayın.


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

öğekontrol edin

Bir düzenin belirli bir öğeyi içerdiğini kontrol etmek için, Set:contains() kullanın.


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

Ek yöntemler

Setler için diğer yararlı işlemler uygulanabilir, böylece setler arasında öğeleri karşılaştırabilir, setleri birleştirebilir veya bir seti diğerinden çıkarabilirsiniz.

Kesişme

Setleri Venn diyagramları olarak düşündüğünüzde, iki setin kesişimini alabilirsiniz, yani her iki sette görünen öğeler.


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

Birleşim

İki setin birleşimini aşağıdaki işlevle alabilirsiniz, yani her iki setteki öğelerin kopyasız bir koleksiyonunu.Bu işlevin __add ek bir kısayol sağlamak için metatable set1 + set2 yöntemini kullandığını unutmayın.


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() -- Kayısı, Limon, Elma, Kiraz, Limon, Mango

Keskinleme

Bir setten diğer bir setteki öğelere tüm öğeleri kaldırabilirsiniz, aşağıdaki işlev aracılığıyla.Yukarıdaki işlevle benzer şekilde, bunun __sub çıkarma kısayolunu sağlamak için metatable set1 - set2 yöntemi kullanılır.


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