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