Metatable

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Metatable memungkinkan tabel menjadi lebih kuat daripada sebelumnya. Mereka terpasang pada data dan berisi nilai-nilai yang disebut metamethod. Metamethod diaktifkan ketika aksi tertentu digunakan dengan data yang terpasang tersebut.

Memanipulasi metatables

Dua fungsi utama untuk menambah dan menemukan metatable tabel adalah setmetatable() dan getmetatable().


local x = {}
local metaTable = {} -- Metatables juga adalah tabel!
setmetatable(x, metaTable) -- Berikan x metatable yang disebut metaTable!
print(getmetatable(x)) --> table: [alamat memori heksadesimal]

Fungsi setmetatable() juga mengembalikan tabel yang Anda atur metatable-nya, sehingga kedua skrip ini melakukan hal yang sama:


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

local x = setmetatable({}, {})

Metamethod

Metamethod adalah fungsi yang disimpan di dalam metatable. Mereka bisa melakukan mulai dari memanggil tabel, hingga menambahkan tabel, bahkan membagi tabel juga. Berikut adalah daftar metamethod yang tersedia:

MetodeDeskripsi
__index(table, index)Diaktifkan ketika table[index] diindeks, jika table[index] adalah nil. Juga dapat diatur ke tabel, dalam hal ini tabel itu akan diindeks.
__newindex(table, index, value)Diaktifkan ketika table[index] mencoba diatur (table[index] = value), jika table[index] adalah nil. Juga dapat diatur ke tabel, dalam hal ini tabel itu akan diindeks.
__call(table, ...)Diaktifkan ketika tabel dipanggil seperti fungsi, ... adalah argumen yang diberikan.
__concat(table, value)Diaktifkan ketika operator penggabungan .. digunakan pada tabel.
__unm(table)Diaktifkan ketika operator unarium digunakan pada tabel.
__add(table, value)Operator penjumlahan +.
__sub(table, value)Operator pengurangan .
__mul(table, value)Operator perkalian *.
__div(table, value)Operator pembagian /.
__idiv(table, value)Operator pembagian bulat //.
__mod(table, value)Operator modulus %.
__pow(table, value)Operator eksponen ^.
__tostring(table)Diaktifkan ketika tostring dipanggil pada tabel.
__metatableJika ada, mengunci metatable sehingga getmetatable() akan mengembalikan ini alih-alih metatable dan setmetatable() akan menghasilkan kesalahan. Nilai non-fungsi.
__eq(table, value)Operator sama dengan ==¹
__lt(table, value)Operator kurang dari <¹
__le(table, value)Operator kurang dari sama dengan <=¹
__modeDigunakan pada tabel lemah, mendeklarasikan apakah kunci dan/atau nilai tabel lemah. Perhatikan bahwa referensi ke instance Roblox tidak pernah lemah. Tabel yang menyimpan referensi semacam itu tidak akan pernah dikumpulkan oleh garbage collector.
__len(table)Diaktifkan ketika operator panjang # digunakan pada objek.
__iter(table)Digunakan untuk menandakan iterator kustom ketika menggunakan iterasi umum.

Perlu dicatat bahwa ketika menulis fungsi untuk metamethod aritmatika atau relasional, dua parameter fungsi dapat dipertukarkan antara tabel yang mengaktifkan metamethod dan nilai lainnya. Misalnya, ketika melakukan operasi vektor dengan skalar, pembagian tidak komutatif. Oleh karena itu jika Anda sedang menulis metamethod untuk kelas vector2 Anda sendiri, Anda harus berhati-hati untuk mempertimbangkan kedua skenario.


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 skalar, vektor = a, b
return vector2.new(skalar / vektor.x, skalar / vektor.y)
elseif type(b) == "number" then
-- a adalah vektor, b adalah skalar
local vektor, skalar = a, b
return vector2.new(vektor.x / skalar, vektor.y / skalar)
elseif (a.__type and a.__type == "vector2" and b.__type and b.__type == "vector2") then
-- baik a maupun 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 metatables, misalnya metamethod __unm untuk membuat tabel menjadi negatif:


local metatable = {
__unm = function(t) -- __unm untuk operator unarium -
local negated = {}
for key, value in t do
negated[key] = -value -- negasikan semua nilai dalam tabel ini
end
return negated -- kembalikan tabel
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
print(table.concat(-table1, "; ")) --> -10; -11; -12

Berikut adalah cara menarik untuk mendeklarasikan sesuatu menggunakan __index:


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

__index diaktifkan ketika x diindeks di dalam tabel dan tidak ditemukan. Luau kemudian mencari tabel __index untuk indeks bernama x, dan, setelah menemukannya, mengembalikannya.

Sekarang Anda dapat dengan mudah melakukan itu dengan fungsi sederhana, tetapi ada banyak lagi dari mana itu berasal. Ambil contohnya ini:


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

Biasanya Anda tidak bisa memanggil tabel, tetapi dengan metatables Anda bisa:


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 tempatkan di tabel baru (t).
end
return unpack(sum) -- Kembalikan nilai tabel individual
end
}
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35

Anda juga bisa melakukan banyak hal lainnya, seperti menambahkan tabel:


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

Ini akan menghasilkan kesalahan yang mengatakan bahwa Anda mencoba melakukan aritmetika pada tabel, tetapi ini berfungsi jika dicoba dengan metatable:


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 metatables, Anda mungkin menemui beberapa masalah. Jika Anda perlu menggunakan metamethod __index untuk membuat nilai baru di dalam tabel, tetapi metatable tabel itu juga memiliki metamethod __newindex, Anda harus menggunakan fungsi bawaan Luau rawset() untuk mengatur nilai tanpa memicu metamethod. Ambil kode berikut sebagai contoh tentang apa yang terjadi jika Anda tidak menggunakan fungsi-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 biasa
end
})
print(t[1]) -- Menyebabkan stack overflow

Stack overflow terjadi ketika Anda mencoba memanggil fungsi dari dirinya sendiri terlalu banyak kali. Dalam fungsi __index di atas, self[i] diatur ke sebuah nilai, jadi ketika sampai ke baris berikutnya, self[i] seharusnya ada dan diyakini tidak akan memanggil metamethod __index. Masalahnya adalah __newindex tidak membiarkan Anda mengatur nilai. Keberadaannya menghentikan nilai dari 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 biasa
end
})
print(t[1]) --> 10

Gunakan tipe data set

Sebuah set adalah koleksi item tanpa urutan dan tanpa elemen duplikat. Sebuah item adalah atau bukan termasuk dalam set. Dengan menggunakan metatables, Anda dapat membangun dan memanipulasi set dalam skrip Luau.

Metode dasar

Kode berikut mencakup fungsionalitas dasar set, memungkinkan Anda membangun set baru, menambahkan dan menghapus item, memeriksa apakah set berisi item, dan mengeluarkan isi set.


local Set = {}
Set.__index = Set
-- Fungsi untuk membangun 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 set
function Set:add(item)
self[item] = true
end
-- Fungsi untuk menghapus item dari set
function Set:remove(item)
self[item] = nil
end
-- Fungsi untuk memeriksa apakah set berisi item
function Set:contains(item)
return self[item] == true
end
-- Fungsi untuk mengeluarkan set sebagai daftar dipisahkan 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 set

Set baru dapat dibangun dengan memanggil Set.new() dengan array opsional dari item untuk ditambahkan.


local fruits = Set.new({"Apel", "Lemon", "Jeruk", "Ceri", "Lime", "Persik"})

Perhatikan bahwa secara definisi, set tidak memiliki konsep urutan.

Tambahkan item

Menambahkan item ke set yang sudah ada dapat dilakukan melalui metode Set:add().


local fruits = Set.new({"Apel", "Lemon", "Jeruk", "Ceri", "Lime", "Persik"})
fruits:add("Mangga")

Hapus item

Untuk menghapus item dari set, panggil Set:remove() dengan nama item.


local fruits = Set.new({"Apel", "Lemon", "Jeruk", "Ceri", "Lime", "Persik"})
fruits:remove("Jeruk")

Periksa untuk item

Untuk memeriksa apakah set berisi item tertentu, gunakan Set:contains().


local fruits = Set.new({"Apel", "Lemon", "Jeruk", "Ceri", "Lime", "Persik"})
local result1 = fruits:contains("Ceri")
print(result1) -- true
local result2 = fruits:contains("Semangka")
print(result2) -- false

Metode tambahan

Operasi yang berguna lainnya dapat diimplementasikan untuk set, memungkinkan Anda membandingkan item antara set, menggabungkan set, atau mengurangi satu set dari yang lain.

Irisan

Ketika mempertimbangkan set sebagai diagram Venn, Anda dapat mendapatkan irisan dari dua set sebagai berikut, yang berarti item yang muncul di kedua 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({"Mangga", "Lemon", "Jeruk", "Ceri", "Lime", "Persik"})
local frozenFruits = Set.new({"Mangga", "Persik", "Nanas"})
local commonFruits = getIntersection(freshFruits, frozenFruits)
commonFruits:output() -- Mangga, Persik

Gabungan

Anda dapat mendapatkan gabungan dari dua set dengan fungsi berikut, yang berarti koleksi item di kedua set tanpa duplikat. Perhatikan bahwa fungsi ini menggunakan metode metatable __add untuk memberikan pintasan penjumlahan 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({"Apel", "Mangga", "Ceri", "Persik"})
local sourFruits = Set.new({"Lemon", "Lime"})
local allFruits = sweetFruits + sourFruits
allFruits:output() -- Persik, Lime, Apel, Ceri, Lemon, Mangga

Pengurangan

Anda dapat menghapus semua item dalam satu set dari item di set lainnya melalui fungsi berikut. Mirip dengan fungsi di atas, ini menggunakan metode metatable __sub untuk memberikan pintasan pengurangan 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({"Apel", "Lemon", "Mangga", "Ceri", "Lime", "Persik"})
local sourFruits = Set.new({"Lemon", "Lime"})
local sweetFruits = allFruits - sourFruits
sweetFruits:output() -- Mangga, Apel, Ceri, Persik
©2026 Roblox Corporation. Roblox, logo Roblox, dan Powering Imagination termasuk dalam merek dagang kami yang terdaftar dan tidak terdaftar di AS dan negara lainnya.