เมทาเมธอดทางเลขคณิต
โอเวอร์โหลด +, -, *, / และตัวดำเนินการอื่น ๆ ด้วยเมทาเมธอด
เมทาเมธอดทางเลขคณิต เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Lua Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
ชื่อเมธอดแปลงค่า
Lua กำหนดเมธอดแปลงค่าสำหรับตัวดำเนินการเลขคณิตทั้งหมด เมื่อ Lua พบการดำเนินการทางเลขคณิตกับตาราง จะค้นหาเมธอดแปลงค่าที่ตรงกันในเมตาเทเบิลของตาราง หากตัวถูกดำเนินการทั้งสองเป็นตาราง Lua จะตรวจสอบเมตาเทเบิลของตัวถูกดำเนินการด้านซ้ายก่อน
-- Operator -> Metamethod
-- a + b -> __add
-- a - b -> __sub
-- a * b -> __mul
-- a / b -> __div
-- a % b -> __mod
-- a ^ b -> __pow
-- a // b -> __idiv
-- -a -> __unm (unary minus)
-- #a -> __len
print("Metamethods defined for all Lua operators")__add สำหรับการบวกเวกเตอร์
กำหนด __add ให้กับตารางเวกเตอร์เพื่อรองรับ + เมธอดแปลงค่าจะได้รับตัวถูกดำเนินการสองตัวและคืนค่าใหม่ ทั้งสองตัวอาจเป็นตาราง หรือหนึ่งตัวอาจเป็นตัวเลขก็ได้ ดังนั้นเมธอดแปลงค่าของคุณควรรองรับทั้งสองกรณี
local Vec = {}
Vec.__index = Vec
Vec.__add = function(a, b)
return setmetatable({x=a.x+b.x, y=a.y+b.y}, Vec)
end
Vec.__tostring = function(v)
return string.format("Vec(%g,%g)", v.x, v.y)
end
function Vec.new(x,y) return setmetatable({x=x,y=y},Vec) end
local v1 = Vec.new(1,2)
local v2 = Vec.new(3,4)
print(tostring(v1 + v2)) -- Vec(4,6)__sub __mul __div
กำหนด __sub, __mul และ __div ในลักษณะเดียวกัน สำหรับการคูณ ให้รองรับทั้งกรณี table*table และ table*number โดยตรวจสอบชนิดของตัวถูกดำเนินการภายในเมธอดแปลงค่า
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__sub = function(a,b) return V(a.x-b.x, a.y-b.y) end
Vec.__mul = function(a,b)
if type(a)=="number" then return V(a*b.x, a*b.y)
elseif type(b)=="number" then return V(a.x*b, a.y*b)
else return a.x*b.x + a.y*b.y -- dot product
end
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end
local v = V(3,4)
print(tostring(v * 2)) -- (6,8)
print(tostring(V(1,0) - V(0,1))) -- (1,-1)__unm การลบแบบเอกภาค
__unm คือเมธอดแปลงค่าสำหรับการลบแบบเอกภาค ซึ่งถูกเรียกเมื่อ Lua ประเมินค่า -obj เมธอดนี้ได้รับตัวถูกดำเนินการ โดยส่งค่าเดียวกันซ้ำสองครั้งเพื่อความสอดคล้อง และคืนค่าที่มีเครื่องหมายตรงข้าม
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__unm = function(a) return V(-a.x, -a.y) end
Vec.__tostring = function(v)
return string.format("(%g,%g)", v.x, v.y)
end
local v = V(3, -4)
print(tostring(-v)) -- (-3,4)
print(tostring(-(-v))) -- (3,-4)__len สำหรับความยาวแบบกำหนดเอง
__len จะถูกเรียกเมื่อประเมินค่า #obj กับตารางที่ไม่มีลำดับจำนวนเต็มดิบ กำหนดให้คืนค่า “ความยาว” ที่มีความหมายสำหรับชนิดข้อมูลแบบกำหนดเอง เช่น เซต คิว หรือโครงสร้างที่มีน้ำหนัก
local Bag = {}
Bag.__index = Bag
Bag.__len = function(b) return b._count end
function Bag.new()
return setmetatable({_count=0, _items={}}, Bag)
end
function Bag:add(item, qty)
self._items[item] = (self._items[item] or 0) + (qty or 1)
self._count = self._count + (qty or 1)
end
local bag = Bag.new()
bag:add("apple", 3)
bag:add("banana", 2)
print(#bag) -- 5__mod และ __pow
__mod จัดการตัวดำเนินการ % ส่วน __pow จัดการ ^ ตัวดำเนินการเหล่านี้พบไม่บ่อยนัก แต่มีประโยชน์สำหรับชนิดข้อมูลตัวเลขแบบกำหนดเอง เช่น จำนวนเต็มขนาดใหญ่ เศษส่วน หรือวัตถุเลขคณิตมอดุลาร์
local Modular = {}
Modular.__index = Modular
local M = 1000000007
local function mod(n)
return setmetatable({n = n % M}, Modular)
end
Modular.__add = function(a,b) return mod(a.n + b.n) end
Modular.__mul = function(a,b) return mod(a.n * b.n) end
Modular.__pow = function(a,b)
local r, base, exp = mod(1), a, b
while exp > 0 do
if exp%2==1 then r = r*base end
base = base*base; exp = math.floor(exp/2)
end
return r
end
print((mod(2) ^ 30).n) -- 73741817 (2^30 mod 1e9+7)__concat
__concat จะถูกเรียกโดยตัวดำเนินการ .. เมื่อมีตัวถูกดำเนินการอย่างน้อยหนึ่งตัวที่มีเมธอดแปลงค่านี้ ทำให้คุณกำหนดการต่อข้อมูลสำหรับชนิดข้อมูลแบบกำหนดเอง หรือสร้าง DSL แบบต่อคำสั่งได้
local Builder = {}
Builder.__index = Builder
Builder.__concat = function(a, b)
local result = {}
for _, v in ipairs(a._parts) do result[#result+1] = v end
if type(b) == "string" then result[#result+1] = b
else for _, v in ipairs(b._parts) do result[#result+1] = v end end
return setmetatable({_parts=result}, Builder)
end
Builder.build = function(b) return table.concat(b._parts) end
local function S(s) return setmetatable({_parts={s}},Builder) end
print((S("Hello") .. ", " .. S("World") .. "!"):build())เมธอดแปลงค่าสำหรับการเปรียบเทียบ
__eq กำหนดการทำงานของ == สำหรับตาราง โดยจะถูกเรียกเฉพาะเมื่อตัวถูกดำเนินการทั้งสองมีเมตาเทเบิลเดียวกัน __lt กำหนด < ส่วน __le กำหนด <= หมายเหตุ: ~= ใช้ __eq; > ใช้ __lt โดยสลับลำดับอาร์กิวเมนต์; >= ใช้ __le
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__eq = function(a,b) return a.x==b.x and a.y==b.y end
Vec.__lt = function(a,b)
return (a.x^2+a.y^2) < (b.x^2+b.y^2) -- by magnitude
end
print(V(1,2) == V(1,2)) -- true
print(V(1,2) == V(1,3)) -- false
print(V(1,0) < V(2,0)) -- true (1 < 2)การเชื่อมเมธอดแปลงค่า
เนื่องจากเมธอดแปลงค่าคืนค่า ซึ่งโดยทั่วไปเป็นตารางใหม่ การดำเนินการจึงสามารถเชื่อมต่อกันได้อย่างเป็นธรรมชาติ ตัวดำเนินการแต่ละตัวจะคืนวัตถุใหม่ และตัวดำเนินการถัดไปจะใช้ผลลัพธ์นั้น วิธีนี้ทำให้สามารถเขียนนิพจน์เลขคณิตแบบต่อเนื่องกับชนิดข้อมูลแบบกำหนดเองได้
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__add = function(a,b) return V(a.x+b.x,a.y+b.y) end
Vec.__mul = function(a,b)
if type(b)=="number" then return V(a.x*b,a.y*b) end
return V(a.x*b.x+a.y*b.y, 0) -- simplified
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end
local result = V(1,0) + V(0,1) * 3
print(tostring(result)) -- (1,3)การดำเนินการกับชนิดข้อมูลผสม
เมื่อเขียน vec * 2 ตัวถูกดำเนินการด้านซ้ายคือตาราง เมื่อเขียน 2 * vec ตัวถูกดำเนินการด้านซ้ายคือตัวเลข ซึ่งไม่มีเมธอดแปลงค่า ดังนั้น Lua จะตรวจสอบเมตาเทเบิลของตัวถูกดำเนินการด้านขวาเพื่อหา __mul เมธอดแปลงค่าของคุณควรรองรับทั้งสองลำดับ
local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__tostring = function(v) return "("..v.x..","..v.y..")" end
Vec.__mul = function(a, b)
if type(a) == "number" then
return V(a*b.x, a*b.y) -- scalar * vec
elseif type(b) == "number" then
return V(a.x*b, a.y*b) -- vec * scalar
end
return a.x*b.x + a.y*b.y -- dot product
end
print(tostring(V(1,2) * 3)) -- (3,6)
print(tostring(3 * V(1,2))) -- (3,6)ตรวจสอบด่วน
เมธอดแปลงค่าใดถูกเรียกใช้โดย -myTable
ทบทวน: เมธอดแปลงค่าทางเลขคณิต
สรุป:
__add __sub __mul __div __mod __pow __idiv— การดำเนินการเลขคณิตแบบทวิภาค__unm— การลบแบบเอกภาค;__len— ตัวดำเนินการ #__concat— ตัวดำเนินการ..__eq __lt __le— ตัวดำเนินการเปรียบเทียบ- จัดการชนิดข้อมูลผสมระหว่างตัวเลขและตารางภายในเมธอดแปลงค่า
คำถามที่พบบ่อย
บทเรียน “เมทาเมธอดทางเลขคณิต” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เมทาเมธอดทางเลขคณิต” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เมทาเมธอดทางเลขคณิต”
โอเวอร์โหลด +, -, *, / และตัวดำเนินการอื่น ๆ ด้วยเมทาเมธอด คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “เมทาเมธอดทางเลขคณิต” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม
ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- รู้จักเมทาเทเบิล
- __index และ __newindex
- เมทาเมธอดทางเลขคณิต
- __tostring และ __len