รู้จักเมทาเทเบิล
กำหนดและอ่านเมทาเทเบิลด้วย setmetatable/getmetatable
รู้จักเมทาเทเบิล เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Lua Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
Metatable คืออะไร
metatable คือตาราง Lua ปกติที่ควบคุมพฤติกรรมของตารางอีกตัวหนึ่ง เมื่อ Lua พบการดำเนินการที่ไม่สามารถทำกับตารางได้ เช่น การคำนวณทางคณิตศาสตร์หรือการเข้าถึงคีย์ที่ไม่มีอยู่ ระบบจะค้นหา เมทาเมธอด ที่สอดคล้องกันในเมตาเทเบิล นี่คือกลไกการขยายความสามารถของ Lua สำหรับการโอเวอร์โหลดตัวดำเนินการและการเขียนโปรแกรมเชิงวัตถุ
local t = {}
local mt = {__index = function(_, k) return "default_" .. k end}
setmetatable(t, mt)
print(t.foo) -- default_foo
print(t.bar) -- default_bar
print(t[1]) -- default_1setmetatable และ getmetatable
setmetatable(t, mt) กำหนดเมตาเทเบิลของ t ให้เป็น mt และคืนค่า t ส่วน getmetatable(t) จะคืนค่าเมตาเทเบิล หรือ nil หากไม่มี คุณสามารถป้องกันไม่ให้มีการเปลี่ยนแปลงเมตาเทเบิลได้ด้วยการกำหนด mt.__metatable = "protected"
local t = {x = 10}
local mt = {}
setmetatable(t, mt)
print(getmetatable(t) == mt) -- true
-- Protect metatable
mt.__metatable = "locked"
print(getmetatable(t)) -- locked
-- setmetatable(t, {}) -- ERROR: cannot change protected metatable__index ในรูปแบบตาราง
เมื่อ __index เป็นตาราง Lua จะค้นหาคีย์ที่ไม่มีอยู่ในตารางนั้น นี่เป็นพื้นฐานของการสืบทอดต้นแบบใน Lua หากไม่มีคีย์ดังกล่าวใน __index เช่นกัน Lua จะตรวจสอบเมตาเทเบิลของตารางนั้นต่อไปตามลำดับชั้น
local Animal = {sound = "...", legs = 4}
local Dog = setmetatable({sound = "Woof"}, {__index = Animal})
local Cat = setmetatable({sound = "Meow"}, {__index = Animal})
print(Dog.sound) -- Woof (own field)
print(Dog.legs) -- 4 (from Animal)
print(Cat.sound) -- Meow
print(Cat.legs) -- 4__index ในรูปแบบฟังก์ชัน
เมื่อ __index เป็นฟังก์ชัน Lua จะเรียกฟังก์ชันนั้นพร้อมตารางและคีย์ที่ไม่มีอยู่ ฟังก์ชันสามารถคำนวณหรือดึงค่าแบบไดนามิกได้ ให้คืนค่า nil จาก __index เพื่อระบุว่า "ไม่พบคีย์"
local dynamic = setmetatable({}, {
__index = function(t, k)
if k:sub(1,4) == "get_" then
local field = k:sub(5)
return function(self) return self[field] end
end
return nil
end
})
dynamic.name = "Lua"
local getter = dynamic.get_name
print(getter(dynamic)) -- Luarawget และ rawset
rawget(t, k) อ่านคีย์ของตารางโดยไม่เรียกใช้ __index ส่วน rawset(t, k, v) กำหนดคีย์โดยไม่เรียกใช้ __newindex ใช้ฟังก์ชันเหล่านี้เพื่อข้ามเมทาเมธอดเมื่อต้องการเข้าถึงตารางโดยตรงภายในเมทาเมธอด และหลีกเลี่ยงการเรียกซ้ำไม่รู้จบ
local logged = setmetatable({}, {
__newindex = function(t, k, v)
print("Setting", k, "=", v)
rawset(t, k, v) -- bypass __newindex
end
})
logged.x = 10 -- Setting x = 10
logged.x = 20 -- no log! key now exists in t
print(logged.x) -- 20หลายตารางใช้เมตาเทเบิลร่วมกัน
เมตาเทเบิลหนึ่งรายการสามารถใช้ร่วมกันโดยหลายตารางได้ นี่คือหลักการทำงานของระบบคลาสใน Lua โดยอินสแตนซ์ทั้งหมดของคลาสหนึ่งจะใช้เมตาเทเบิลเดียวกัน ซึ่งเก็บเมธอดต่าง ๆ ไว้ การเปลี่ยนแปลงเมตาเทเบิลจะส่งผลต่ออินสแตนซ์ทั้งหมด
local Mt = {
__index = {
greet = function(self)
print("Hello from " .. (self.name or "?"))
end
}
}
local a = setmetatable({name="Alice"}, Mt)
local b = setmetatable({name="Bob"}, Mt)
a:greet() -- Hello from Alice
b:greet() -- Hello from Bobฟิลด์ __metatable
การกำหนด mt.__metatable เป็นค่าใด ๆ จะทำให้ getmetatable คืนค่านั้นแทนเมตาเทเบิลจริง วิธีนี้จะป้องกันไม่ให้ผู้ใช้ตรวจสอบหรือแทนที่เมตาเทเบิล ซึ่งมีประโยชน์สำหรับการห่อหุ้มและความปลอดภัย
local secret = setmetatable({}, {
__metatable = false, -- hide metatable
__index = {value = 42}
})
print(secret.value) -- 42
print(getmetatable(secret)) -- false (not the real mt)
-- setmetatable(secret, {}) -- ERRORการตรวจสอบเมตาเทเบิล
ใช้ getmetatable(t) เพื่อตรวจสอบว่าวัตถุมีเมตาเทเบิลที่ระบุหรือไม่ เช่น สำหรับตรวจสอบชนิดข้อมูล เนื่องจาก __metatable สามารถซ่อนเมตาเทเบิลจริงได้ จึงควรใช้ rawequal หรือฟิลด์ตัวบ่งชี้เพื่อให้การตรวจสอบอินสแตนซ์เชื่อถือได้
local MyClass = {}
MyClass.__index = MyClass
MyClass.__metatable = MyClass -- use self as marker
function MyClass.new(x)
return setmetatable({x=x}, MyClass)
end
local obj = MyClass.new(5)
print(getmetatable(obj) == MyClass) -- true
print(obj.x) -- 5เมตาเทเบิลกับสิ่งที่ไม่ใช่ตาราง
สตริงใน Lua มีเมตาเทเบิลอยู่แล้ว ซึ่งก็คือโมดูล string นั่นเป็นเหตุผลที่คุณสามารถเรียก s:upper() กับสตริงใด ๆ ได้ ใน Lua ล้วน ๆ คุณไม่สามารถกำหนดเมตาเทเบิลให้สตริง ตัวเลข หรือค่าบูลีนได้ ทำได้เฉพาะกับตารางและ userdata เท่านั้น
local s = "hello"
local mt = getmetatable(s)
-- String metatable has __index = string library
print(mt.__index == string) -- true
-- So all string functions are methods:
print(s:upper()) -- HELLO
print(s:rep(3, "-")) -- hello-hello-helloการแก้จุดบกพร่องด้วยเมตาเทเบิล
คุณสามารถเพิ่มเมธอดแปลงค่า __tostring เพื่อควบคุมวิธีที่ tostring() และ print() ใช้แสดงตารางได้ ความสามารถนี้มีประโยชน์อย่างมากสำหรับการแก้จุดบกพร่องของวัตถุที่ซับซ้อน
local Point = {}
Point.__index = Point
Point.__tostring = function(p)
return string.format("Point(%g, %g)", p.x, p.y)
end
function Point.new(x, y)
return setmetatable({x=x,y=y}, Point)
end
local p = Point.new(3, 4)
print(tostring(p)) -- Point(3, 4)
print(p) -- Point(3, 4) (print calls tostring)ตรวจสอบด่วน
จะเกิดอะไรขึ้นเมื่อคุณเข้าถึงคีย์ที่ไม่พบในตารางซึ่งมีเมตาเทเบิลที่กำหนด __index ให้เป็นอีกตารางหนึ่ง
ทบทวน: เมตาเทเบิล
สรุป:
setmetatable(t, mt)/getmetatable(t)__index: ตาราง → ค้นหาในต้นแบบ; ฟังก์ชัน → ส่งต่อแบบไดนามิกrawget/rawsetข้ามการทำงานของเมธอดแปลงค่า- เมตาเทเบิลที่ใช้ร่วมกันทำให้เกิดพฤติกรรมคล้ายคลาส
__metatableป้องกันการตรวจสอบเมตาเทเบิล__tostringควบคุมผลลัพธ์ของการแสดงผล
เรียนรู้ Lua ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 40
- บทเรียน
- 159
คำถามที่พบบ่อย
บทเรียน “รู้จักเมทาเทเบิล” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “รู้จักเมทาเทเบิล” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “รู้จักเมทาเทเบิล”
กำหนดและอ่านเมทาเทเบิลด้วย setmetatable/getmetatable คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “รู้จักเมทาเทเบิล” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม
ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- รู้จักเมทาเทเบิล
- __index และ __newindex
- เมทาเมธอดทางเลขคณิต
- __tostring และ __len