ตารางเมทาช่วยให้ตารางมีประสิทธิภาพมากขึ้นกว่าที่เคยพวกเขาจะถูกแนบไปกับข้อมูลและมีค่าที่เรียกว่า 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 doprint(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