โมเทตาเบิล

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

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

พิจารณารหัสต่อไปนี้:


local list = {1, 2}
print(list[3])

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

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

สองหน้าที่สำคัญสำหรับการเพิ่มและการค้นหาตารางโดยใช้เมทาเทล, คือ setmetatable และ getmetatable


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

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


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

local x = setmetatable({}, {})

เมทามีธิดา

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

วิธีคำอธิบาย
__index(ตาราง, ดัชนี)เปิดใช้งานเมื่อ table[index] ได้รับการดัดผ้าเมื่อสร้างตารางแล้ว หาก table[index] เป็น zero สามารถตั้งได้ในตาราง ในกรณีนี้ตารางจะถูกดัดผ้า
__ใหม่ในดัชนี (ตาราง, ดัชนี, มูลค่า)เกิดขึ้นเมื่อ table[index] พยายามต้องการตั้ง (table[index] = value) หาก table[index] เป็น zero สามารถตั้งได้ที่โต๊ะ ในกรณีนี้โต๊ะจะถูกดัดผม
__call(ตาราง, ...)จะเริ่มต้นไฟร์เมื่อตารางถูกเรียกใช้เหมือนฟังก์ชัน... เป็นข้อมูลที่ผ่าน
__concat(ตาราง, value)จะเกิดขึ้นเมื่อผู้ประกอบการคําสั่ง .. ใช้ในตาราง
__unm(โต๊ะ)จะเกิดขึ้นเมื่อผู้ประกอบการ - ผู้ให้บริการใช้ในตาราง
__add(ตาราง, value)ตัวประกอบ +
__sub(ตาราง, value)The - ตัวดูดออก
__mul(ตาราง, value)ตัวประมวลผล *
__div(ตาราง, value)ตัวประกอบ / บริษัท การแบ่งย่อย
__idiv(ตาราง, value)The // หน่วยการแบ่งชั้น
__mod(ตาราง, value)ผู้ประกอบการ modulus %
__pow(ตาราง, value)ตัวประกอบการ ^ การเอาตัว
__tostring(โตริง)จุดเกิดเหตุเมื่อต้นไม้ถูกเรียกในตาราง
__ตารางหากมีให้ปัจจุบันจะล็อคตารางโต้ตอบให้เก็บข้อมูลตารางโต้ตอบนี้แทนที่จะเป็นตารางโต้ตอบและตารางโต้ตอบจะผิดพลาด ไม่ใช่ค่าตัว
__eq(ตาราง, value)== เท่ากับผู้ประกอบการ¹
__lt(ตาราง, value)The < น้อยกว่า operator¹
__le(ตาราง, value)ผู้ประกอบการ ¹
__โหมดใช้ในตารางอ่อนแอ ระบุว่ามีคีย์และ/หรือมีค่าของตารางอ่อนแอหรือไม่ หมายเหตุ: การอ้างอิงถึงติดตั้ง Roblox จะไม่เคยอ่อนแอ ตารางที่มีคีย์เหล่านี้จะไม่เคยถูกเก็บขยะ
__gc(โต๊ะ)ไฟร์เมื่อตารางเก็บขยะ หมายเหตุ: บน Roblox คุณสมบัตินี้ถูกปิดใช้งาน
__len(โต๊ะ)ไฟร์เมื่อตัวประกอบที่มีความยาว # ใช้งาน
__iter(โต๊ะ)ใช้เพื่อระบุไอเทอร์ที่กำหนดเองเมื่อใช้งานไอเทอร์ทั่วไป

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


local vector2 = {__type = "vector2"}
local mt = {__index = vector2}
function mt.__div(a, b)
if type(a) == "number" then
-- a เป็นสกุลเลข บเป็นベクトอร์
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

การใช้งาน Metatables

มีหลายวิธีในการใช้ metatables เช่น metamethode ของ __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 ถูกดัดผมในตารางและไม่พบ ลูอาจาร์จากนั้นค้นหาผ่านตาราง __index สําหรับดัดผมที่มีชื่อว่า x และหาหนึ่ง แล้วกลับมาที่นี่และแสดงผลเป็น 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

นี่จะเกิดข้อผิดพลาดโดยการพูดว่าคุณกำลังพยายามที่จะทำ arithmetic บนตาราง ลองใช้นี้กับ 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 มีมีธีมีเพียงเพื่อให้มันเรียบง่าย:


local function mathProblem(num)
for i = 1, 20 do
num = math.floor(num * 10 + 65)
end
for i = 1, 10 do
num += i - 1
end
return num
end
local metatable = {
__index = function(object, key)
local num = mathProblem(key)
object[key] = num
return num
end
}
local t = setmetatable({}, metatable)
print(t[1]) -- จะช้าลงเพราะเป็นครั้งแรกที่ใช้ตัวเลขนี้ดังนั้นจึงต้องประมาณค่าตัวเลข
print(t[2]) -- จะช้าลงเพราะเป็นครั้งแรกที่ใช้หมายเลขนี้
print(t[1]) -- will be fast because it's just grabbing the number from the table.

Rawset, Rawget, Rawequal

เมื่อเล่นกับ metatables คุณอาจเจอปัญหาบางอย่าง สิ่งที่เกิดขึ้นถ้าคุณต้องใช้ metamethod ในตารางใหม่ แต่ metatable ของตารางนั้นมี metamethod


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 C-Stack overflow

ตอนนี้ทำไมมันจึงจะเป็นการเหยียบทะลุของสแต็ค? เหยียบทะลุของสแต็คเกิดขึ้นเมื่อคุณพยายามที่จะโทรคุณสมบัติจากตัวเ

ปัญหาคือ __newindex ไม่สามารถให้เราตั้งค่ามัน ความประสบการณ์ของมันหยุดให้มูลค่าเพิ่มเข้าตารางด้วยวิธี t[i] = v ที่มาตรฐาน


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]) -- prints 10

การใช้ Set Datatype

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

วิธีการพื้นฐาน

รหัสต่อไปนี้รวมถึงคุณสมบัติพื้นฐาน, ให้คุณสร้างชุดใหม่, ไอเท็ม, ไอเท็ม, ตั้งค่า


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

วิธีการเพิ่มเติม

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

สามสิบหก

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


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

สหภาพ

คุณสามารถรับ สหภาพ ของสองชุดด้วยวิธีต่อไปนี้หมายถึงคอลเลกชันของรายการในทั้งสองชุดโดยไม่มีซ้ำซาก โปรดทราบว่าวิธีนี้ใช้วิธีการ __add ในตารางเดียว


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