Metabel memungkinkan tabel menjadi lebih kuat dari sebelumnya.Mereka terpasang pada data dan berisi nilai yang disebut metode metametode.Metode metametode ditembak ketika tindakan tertentu digunakan dengan datum yang ditautkannya.
Manipulasi tabel metode
Dua fungsi utama untuk menambahkan dan menemukan metabel tabel adalah setmetatable() dan getmetatable() .
local x = {}local metaTable = {} -- metaTables adalah tabel juga!setmetatable(x, metaTable) -- Berikan x tabel yang dapat diakses yang disebut metaTable!print(getmetatable(x)) --> table: [hexadecimal memory address]
Fungsi setmetatable() juga mengembalikan tabel yang Anda atur metabelnya, jadi kedua skrip ini melakukan hal yang sama:
local x = {}setmetatable(x, {})
local x = setmetatable({}, {})
Metode Metamodifikasi
Metode metametode adalah fungsi yang disimpan di dalam metabel.Mereka dapat pergi dari memanggil tabel, menambahkan tabel, hingga bahkan membagi tabel juga.Inilah daftar metode metametode yang tersedia:
Metode | Deskripsi |
---|---|
__index(table, index) | Melepaskan api saat table[index] diindeks, jika table[index] adalah nil . Juga dapat disetel ke tabel, di mana tabel tersebut akan diindeks. |
__newindex(table, index, value) | Melepaskan api saat table[index] mencoba disetel (table[index] = value) , jika table[index] adalah nil .Juga dapat disetel ke tabel, di mana tabel itu akan diindeks. |
__call(table, ...) | Memicu ketika tabel dipanggil seperti fungsi, ... adalah argumen yang disampaikan. |
__concat(table, value) | Memicu ketika operator koncatenasi .. digunakan di atas meja. |
__unm(table) | Memicu ketika operator unary – digunakan di atas meja. |
__add(table, value) | Operator tambahan + . |
__sub(table, value) | Operator pengurangan – . |
__mul(table, value) | Operator penggandaan * multi. |
__div(table, value) | Operator divisi / . |
__idiv(table, value) | Operator pembagian lantai //. |
__mod(table, value) | Operator modul % . |
__pow(table, value) | Operator ekspansi ^ . |
__tostring(table) | Ditembak ketika tostring dipanggil di atas meja. |
__metatable | Jika hadir, mengunci metabel sehingga getmetatable() akan mengembalikan ini bukan metabel dan setmetatable() akan gagal. Nilai tidak berfungsi. |
__eq(table, value) | The == sama dengan operator¹ |
__lt(table, value) | Operator < kurang dari kurang dari operator¹ |
__le(table, value) | Operator <= ¹ |
__mode | Digunakan di tabel lemah, menyatakan apakah kunci dan/atau nilai tabel lemah.Perhatikan bahwa referensi ke instansi Roblox tidak pernah lemah.Tabel yang menyimpan referensi seperti itu tidak akan pernah dikumpulkan sampah. |
__len(table) | Ditembak ketika operator panjang # digunakan pada objek. |
__iter(table) | Digunakan untuk menunjukkan iterator khusus saat menggunakan iterasi umum. |
Harus dicatat bahwa ketika menulis fungsi untuk metode metematika atau relasi, dua parameter fungsi dapat dipertukarkan antara tabel yang menembak metode metematika dan nilai lainnya.Sebagai contoh, saat melakukan operasi vektor dengan pembagian skala tidak komutatif.Oleh karena itu jika Anda menulis metode metametode untuk kelas Anda sendiri vector2, Anda ingin berhati-hati untuk menghitung skenario mana pun.
local vector2 = {__type = "vector2"}
local mt = {__index = vector2}
function mt.__div(a, b)
if type(a) == "number" then
-- a adalah skalar, b adalah vektor
local scalar, vector = a, b
return vector2.new(scalar / vector.x, scalar / vector.y)
elseif type(b) == "number" then
-- a adalah vektor, b adalah skalar
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
-- baik a dan b adalah vektor
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
Penggunaan
Ada banyak cara untuk menggunakan metabel, misalnya metode __unm metametode untuk membuat tabel negatif:
local metatable = {
__unm = function(t) -- __unm adalah untuk operator unary
local negated = {}
for key, value in t do
negated[key] = -value -- menyangkal semua nilai di tabel ini
end
return negated -- 返回 tabel
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
print(table.concat(-table1, "; ")) --> -10; -11; -12
Berikut adalah cara menarik untuk menyatakan hal-hal menggunakan __index :
local metatable = {__index = {x = 1}}local t = setmetatable({}, metatable)print(t.x) --> 1
__index dipecat ketika x diindeks di tabel dan tidak ditemukan.Luau kemudian mencari melalui tabel __index untuk indeks yang disebut x , dan, menemukan satu, mengembalikannya.
Sekarang Anda dapat dengan mudah melakukannya dengan fungsi sederhana, tetapi ada banyak lagi dari mana itu berasal. Ambil contoh ini:
local t = {10, 20, 30}print(t(5))
Biasanya Anda tidak dapat memanggil tabel, tetapi dengan metatabel Anda dapat:
local metatable = {
__call = function(t, param)
local sum = {}
for i, value in ipairs(t) do
sum[i] = value + param -- Tambahkan argumen (5) ke nilai, lalu letakkan di tabel baru (t).
end
return unpack(sum) -- Kembalikan nilai tabel individu
end
}
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35
Anda juga dapat melakukan lebih banyak, seperti menambahkan tabel:
local table1 = {10, 11, 12}local table2 = {13, 14, 15}for k, v in table1 + table2 doprint(k, v)end
Ini akan berisi kesalahan mengatakan bahwa Anda mencoba melakukan aritmatika pada tabel, tetapi berfungsi saat dicoba dengan metabel:
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
Saat bermain dengan metabel, Anda mungkin menghadapi beberapa masalah.Jika Anda perlu menggunakan metode __index metametode untuk membuat nilai baru di tabel, tetapi metode metabel tabel itu juga memiliki metode __newindex metametode, Anda ingin menggunakan fungsi bawaan Luau rawset() untuk mengatur nilai tanpa memanggil metode metametode apa pun.Ambil kode berikut sebagai contoh apa yang terjadi jika Anda tidak menggunakan fungsi ini.
local t = setmetatable({}, {
__index = function(self, i)
self[i] = i * 10
return self[i]
end,
__newindex = function(self, i, v)
-- Jangan atur nilai ke tabel dengan cara normal
end
})
print(t[1]) -- Causes a stack overflow
Kelebihan tumpukan terjadi ketika Anda mencoba memanggil fungsi dari dirinya sendiri terlalu banyak kali.Dalam fungsi __index di atas, self[i] ditetapkan ke nilai, jadi ketika sampai ke baris berikutnya, self[i] harus ada dan kemungkinan tidak akan memanggil metode __index metametode.Masalahnya adalah bahwa __newindex tidak memungkinkan Anda untuk mengatur nilainya.Kehadirannya menghentikan nilai ditambahkan ke tabel dengan metode standar t[i] = v.Untuk melewati ini, gunakan fungsi rawset():
local t = setmetatable({}, {
__index = function(self, i)
rawset(self, i, i * 10)
return self[i]
end,
__newindex = function(self, i, v)
-- Jangan atur nilai ke tabel dengan cara normal
end
})
print(t[1]) --> 10
Gunakan tipe data yang ditetapkan
Satu set adalah koleksi item tanpa urutan dan elemen duplikat.Sebuah item entah adalah atau tidak berada dalam satu atur.Menggunakan metabel, Anda dapat membangun dan memanipulasi set dalam skrip Luau.
Metode dasar
Kode berikut termasuk fungsi set dasar, memungkinkan Anda membuat set baru, menambahkan dan menghapus item, memeriksa apakah set berisi item, dan mengekspor konten atur.
local Set = {}
Set.__index = Set
-- Fungsi untuk membuat satu set dari daftar item opsional
function Set.new(items)
local newSet = {}
for key, value in items or {} do
newSet[value] = true
end
return setmetatable(newSet, Set)
end
-- Fungsi untuk menambahkan item ke atur
function Set:add(item)
self[item] = true
end
-- Fungsi untuk menghapus item dari atur
function Set:remove(item)
self[item] = nil
end
-- Fungsi untuk memeriksa apakah satu set berisi item
function Set:contains(item)
return self[item] == true
end
-- Fungsi untuk mengekspor set sebagai daftar terpisah koma untuk debugging
function Set:output()
local elems = {}
for key, value in self do
table.insert(elems, tostring(key))
end
print(table.concat(elems, ", "))
end
Buat atur
Satu set baru dapat dibangun dengan memanggil Set.new() dengan array opsional item untuk ditambahkan.
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
Perhatikan bahwa secara definisi, satu set tidak memiliki konsep perintah.
Tambahkan item
Menambahkan item ke set yang ada dapat dilakukan melalui metode Set:add().
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})fruits:add("Mango")
Hapus item
Untuk menghapus item dari atur, panggil Set:remove() dengan nama item.
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})fruits:remove("Orange")
Periksa item
Untuk memeriksa apakah satu set berisi item tertentu, gunakan Set:contains() .
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})local result1 = fruits:contains("Cherry")print(result1) -- benarlocal result2 = fruits:contains("Watermelon")print(result2) -- false
Metode tambahan
Operasi berguna lainnya dapat dilaksanakan untuk set, memungkinkan Anda membandingkan item antara set, menggabungkan set, atau mengurangi satu set dari yang lain.
Persimpangan
Saat mempertimbangkan set sebagai diagram Venn, Anda dapat mendapatkan intersepsi dari dua set sebagai berikut, yang berarti item yang muncul di keduanya 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", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
local frozenFruits = Set.new({"Mango", "Peach", "Pineapple"})
local commonFruits = getIntersection(freshFruits, frozenFruits)
commonFruits:output() -- Mango, Peach
Persatuan
Anda dapat mendapatkan persatuan dari dua set dengan fungsi berikut, yang berarti koleksi item di kedua set tanpa duplikat.Perhatikan bahwa fungsi ini menggunakan metode metabel __add untuk memberikan pintas tambahan dari 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() -- Peach, Lime, Apple, Cherry, Lemon, Mango
Pengurangan
Anda dapat menghapus semua item dalam satu set dari item di set lain melalui fungsi berikut.Mirip dengan fungsi di atas, ini menggunakan metode metabel __sub untuk memberikan pintasan pengurangan dari 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