ตารางเมตา

*เนื้อหานี้แปลโดยใช้ AI (เวอร์ชัน Beta) และอาจมีข้อผิดพลาด หากต้องการดูหน้านี้เป็นภาษาอังกฤษ ให้คลิกที่นี่

ตารางเมทาช่วยให้ตารางมีประสิทธิภาพมากขึ้นกว่าที่เคยพวกเขาจะถูกแนบไปกับข้อมูลและมีค่าที่เรียกว่า metamethodsเมทาวิธีถูกเรียกใช้เมื่อใช้การดำเนินการบางอย่างกับข้อมูลที่มันแนบมา

จัดการตารางเมตา

ฟังก์ชันหลักสองฟังก์ชันสำหรับการเพิ่มและค้นหา metatable ของตารางคือ setmetatable() และ getmetatable()


local x = {}
local metaTable = {} -- ตาราง metaTables เป็นตารางเช่นกัน!
setmetatable(x, metaTable) -- ให้ x เป็นโต๊ะที่เรียกว่า metaTable!
print(getmetatable(x)) --> table: [hexadecimal memory address]

ฟังก์ชัน setmetatable() ยังคืนตารางที่คุณกำลังตั้งค่า metatable ดังนั้นสคริปต์ทั้งสองจะทำสิ่งเดียวกัน:


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

local x = setmetatable({}, {})

เมทาวิธีการ

เมทาวิธีคือฟังก์ชันที่จัดเก็บไว้ภายในตารางเมทาพวกเขาสามารถไปจากการโทรหาตารางไปจนถึงการเพิ่มตารางและแม้แต่แบ่งตารางเช่นกันนี่คือรายการของ metamethods ที่มีอยู่:

วิธีคําอธิบาย
__index(table, index)จะเกิดไฟไหม้เมื่อ table[index] ถูกจัดระเบียบ หาก table[index] เป็น nil ก็สามารถตั้งค่าให้เป็นตารางได้ ในกรณีนั้นตารางจะถูกจัดระเบียบ
__newindex(table, index, value)ไฟไหม้เมื่อ table[index] พยายามที่จะตั้งค่า (table[index] = value) ถ้า table[index] เป็น nilยังสามารถตั้งค่าเป็นตารางได้ ในกรณีนั้นตารางจะถูกจัดระเบียบ
__call(table, ...)ไฟเมื่อตารางถูกเรียกเหมือนฟังก์ชัน ... คืออาร์กิวเมนต์ที่ถูกส่ง
__concat(table, value)จะเกิดไฟไหม้เมื่อผู้ปฏิบัติการ concatenation .. ถูกใช้บนตาราง
__unm(table)เกิดไฟไหม้เมื่อผู้ปฏิบัติการ unary ถูกใช้บนตาราง
__add(table, value)ตัวเลือกเพิ่ม +
__sub(table, value)ตัวประกอบการลบ
__mul(table, value)ตัวคูณ * หลาย
__div(table, value)ตัวประกอบการแบ่ง /
__idiv(table, value)ตัวแยกชั้น //
__mod(table, value)ตัวประกอบโมดูล %
__pow(table, value)ตัวเลขทศนิยมของผลบวก ^
__tostring(table)ยิงเมื่อ tostring ถูกเรียกบนตาราง
__metatableหากมี จะล็อค metatable ดังนั้น getmetatable() จะส่งคืนสิ่งนี้แทน metatable และ setmetatable() จะผิดพลาด มูลค่าไม่ทำงาน
__eq(table, value)The == เท่ากับผู้ดําเนินการ¹
__lt(table, value)ตัวประกอบน้อยกว่า < น้อยกว่าผู้ดำเนินการ¹
__le(table, value)ตัวประกอบ <=¹
__modeใช้ในตารางที่อ่อนแอ ประกาศว่ากุญแจและ/หรือมูลค่าของตารางอ่อนแอหรือไม่โปรดทราบว่าการอ้างอิงถึงตัวอย่าง Roblox ไม่เคยอ่อนแอตารางที่มีการอ้างอิงดังกล่าวจะไม่ถูกเก็บขยะเป็นอันขาด
__len(table)ยิงเมื่อผู้ปฏิบัติการความยาว # ถูกใช้บนวัตถุ
__iter(table)ใช้เพื่อระบุตัวต่อรองที่กําหนดเองเมื่อใช้การเลือกแบบทั่วไป

ควรทราบว่าเมื่อเขียนฟังก์ชันสำหรับอาริทเมติกหรือเมทาวิธีที่เกี่ยวข้อง พารามิเตอร์สองตัวสามารถแลกเปลี่ยนระหว่างตารางที่ยิงเมทาวิธีและค่าอื่นได้ตัวอย่างเช่น เมื่อทำการดำเนินการเวกเตอร์ด้วยการแบ่งตัวเลขไม่เป็นการบวกดังนั้นหากคุณกำลังเขียน metamethods สำหรับคลาสของคุณเอง vector2 คุณต้องระวังเพื่อให้บัญชีสำหรับทั้งสองสถานการณ์


local vector2 = {__type = "vector2"}
local mt = {__index = vector2}
function mt.__div(a, b)
if type(a) == "number" then
-- a เป็นเวกเตอร์ b เป็นเวกเตอร์
local scalar, vector = a, b
return vector2.new(scalar / vector.x, scalar / vector.y)
elseif type(b) == "number" then
-- a เป็นเวกเตอร์ b เป็นสเกลาร์
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
-- ทั้ง a และ b เป็นベクトル
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

การใช้งาน

มีหลายวิธีในการใช้ตารางเมทา, ตัวอย่างเช่น __unm เมทาเมธอดที่จะทำให้ตารางเป็นลบ:


local metatable = {
__unm = function(t) -- __unm สำหรับตัวประกอบเดี่ยว - ผู้ดำเนินการ
local negated = {}
for key, value in t do
negated[key] = -value -- ปฏิเสธค่าทั้งหมดในตารางนี้
end
return negated -- ส่งคืนตาราง
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
print(table.concat(-table1, "; ")) --> -10; -11; -12

นี่คือวิธีที่น่าสนใจในการประกาศสิ่งต่างๆโดยใช้ __index :


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

__index ถูกยิงเมื่อ x ถูกจัดระเบียบในตารางและไม่พบLuau จากนั้นค้นหาผ่านตาราง __index เพื่อหาดัชนีที่เรียกว่า x และเมื่อพบหนึ่งรายการ ก็ส่งคืนมันกลับ

ตอนนี้คุณสามารถทำได้ง่ายด้วยฟังก์ชันง่ายๆ แต่มีอีกมากที่มาจากที่นั่น ใช้ตัวอย่างนี้:


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

โดยปกติคุณไม่สามารถเรียกตารางได้ แต่ด้วย metatables คุณสามารถ:


local metatable = {
__call = function(t, param)
local sum = {}
for i, value in ipairs(t) do
sum[i] = value + param -- เพิ่มอาร์กิวเมนต์ (5) ให้กับค่าแล้ววางลงในตารางใหม่ (t)
end
return unpack(sum) -- คืนค่าตารางแต่ละค่า
end
}
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35

คุณสามารถทำได้มากขึ้นอีกด้วย เช่น เพิ่มตาราง:


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

ข้อผิดพลาดนี้จะบอกว่าคุณกําลังพยายามทําการคำนวณบนตาราง แต่จะทํางานเมื่อพยายามด้วย 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

เมื่อเล่นกับตารางเมตาคุณอาจพบปัญหาบางอย่างหากคุณต้องใช้เมทาวิธี __index เพื่อสร้างค่าใหม่ในตาราง แต่ตารางนั้นยังมีเมทาวิธี __newindex ด้วย คุณจะต้องใช้ฟังก์ชัน Luau ที่สร้างไว้ล่วงหน้า rawset() เพื่อตั้งค่าค่าโดยไม่ต้องเรียกใช้เมทาวิธีใดๆใช้รหัสต่อไปนี้เป็นตัวอย่างของสิ่งที่เกิดขึ้นหากคุณไม่ใช้ฟังก์ชันเหล่านี้


local t = setmetatable({}, {
__index = function(self, i)
self[i] = i * 10
return self[i]
end,
__newindex = function(self, i, v)
-- อย่าตั้งค่ามูลค่าไปยังตารางด้วยวิธีปกติ
end
})
print(t[1]) -- Causes a stack overflow

การบรรจุเกินเกิดขึ้นเมื่อคุณพยายามเรียกฟังก์ชันจากตัวเองมากเกินไปหลายครั้งในฟังก์ชัน __index ด้านบน self[i] ถูกตั้งเป็นค่าดังนั้นเมื่อถึงบรรทัดถัดไป self[i] ควรมีอยู่และอาจไม่เรียก metamethod __indexปัญหาคือ __newindex ไม่ให้คุณตั้งค่าได้การอยู่ของมันทำให้ค่าไม่ถูกเพิ่มลงในตารางด้วยวิธี t[i] = v มาตรฐานเพื่อผ่านสิ่งนี้ให้ใช้ฟังก์ชัน rawset() :


local t = setmetatable({}, {
__index = function(self, i)
rawset(self, i, i * 10)
return self[i]
end,
__newindex = function(self, i, v)
-- อย่าตั้งค่ามูลค่าไปยังตารางด้วยวิธีปกติ
end
})
print(t[1]) --> 10

ใช้ชนิดข้อมูลที่กําหนด

ชุด เป็น คือคอลเลกชันของรายการที่ไม่มีลําดับและไม่มีองค์ประกอบซ้ำรายการใด ๆ คือ หรือ ตั้งค่าLuau ได้

วิธีพื้นฐาน

รหัสต่อไปนี้รวมฟังก์ชันการตั้งค่าพื้นฐานที่ช่วยให้คุณสร้างชุดใหม่ เพิ่ม ไอเท็มไอเท็มและส่งออกเนื้อหาของชุด


local Set = {}
Set.__index = Set
-- ฟังก์ชันสร้างชุดจากรายการตัวเลือกของไอเทม
function Set.new(items)
local newSet = {}
for key, value in items or {} do
newSet[value] = true
end
return setmetatable(newSet, Set)
end
-- ตั้งค่า
function Set:add(item)
self[item] = true
end
-- ตั้งค่า
function Set:remove(item)
self[item] = nil
end
-- ไอเท็ม
function Set:contains(item)
return self[item] == true
end
-- ฟังก์ชันเพื่อส่งออกเป็นรายการแยกกับจุลภาคสำหรับการแก้ไขข้อผิดพลาด
function Set:output()
local elems = {}
for key, value in self do
table.insert(elems, tostring(key))
end
print(table.concat(elems, ", "))
end

ตั้งค่า

ชุดใหม่สามารถสร้างได้โดยการโทร Set.new() ด้วยรายการที่เลือกได้เพื่อเพิ่ม


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

โปรดทราบว่าตามความหมายแล้วชุดไม่มีความคิดเรื่องการจัดลําดับ

ไอเท็ม

การเพิ่มรายการในชุดที่มีอยู่แล้วสามารถทำได้โดยใช้วิธี Set:add()


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

ไอเท็ม

เพื่อลบรายการจากชุด โทร Set:remove() ด้วยชื่อรายการ


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

ไอเท็ม

ไอเท็มSet:contains()


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

วิธีเพิ่มเติม

การดำเนินการที่มีประโยชน์อื่นๆ สามารถใช้สำหรับชุดเพื่อให้คุณเปรียบเทียบรายการระหว่างชุด รวมชุด หรือลบชุดหนึ่งออกจากอีก

แยก

เมื่อพิจารณาชุดในฐานะแผนภาพเวนน์ คุณสามารถรับ การแยกทาง ของชุดสองชุดตามที่ระบุไว้ด้านล่าง ซึ่งหมายถึงรายการที่ปรากฏใน ทั้งสองชุด


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

สหภาพ

คุณสามารถรับ สหภาพ ของสองชุดด้วยฟังก์ชันต่อไปนี้ซึ่งหมายถึงคอลเลกชันของรายการในทั้งสองชุดโดยไม่มีซ้ำโปรดทราบว่าฟังก์ชันนี้ใช้วิธีการ metatable __add เพื่อให้สั้นลัดเพิ่มเติมของ 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() -- พีช มะนาว แอปเปิล เชอร์รี่ มะม่วง เลมอน

การหักลบ

คุณสามารถลบรายการทั้งหมดในชุดเดียวจากรายการในชุดอื่นผ่านฟังก์ชันต่อไปนี้คล้ายกับฟังก์ชันด้านบนนี้ใช้วิธีการ metatable __sub เพื่อให้การลบลัดของ 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