0Pricing
Lua Academy · บทเรียน

คลาสผ่านเมทาเทเบิล

จำลองคลาสด้วยตารางและ __index เพื่อค้นหาเมธอด

คลาสผ่านเมทาเทเบิล เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Lua Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

รูปแบบตารางคลาส

ใน Lua “คลาส” เป็นเพียงตารางที่เก็บเมธอด อินสแตนซ์คือตารางที่เมตาเทเบิลมี __index ชี้ไปยังตารางคลาส ทำให้เข้าถึงเมธอดทั้งหมดจากอินสแตนซ์ได้ผ่านสายโซ่การค้นหา

local Animal = {}
Animal.__index = Animal

function Animal.new(name, sound)
  return setmetatable({name=name, sound=sound}, Animal)
end

function Animal:speak()
  print(self.name .. " says " .. self.sound)
end

local dog = Animal.new("Rex","Woof")
dog:speak()  -- Rex says Woof

__index ชี้ไปยังคลาส

การตั้งค่า ClassName.__index = ClassName หมายถึง “ให้ค้นหาคีย์ที่ไม่พบในตารางคลาส” เมื่อเรียกเมธอดของอินสแตนซ์ Lua จะค้นหาในอินสแตนซ์ก่อน จากนั้นตรวจสอบเมตาเทเบิล (__index) พบคลาส แล้วจึงค้นหาเมธอดในคลาสนั้น

local Point = {}
Point.__index = Point

Point.type = "2D Point"

function Point.new(x,y)
  return setmetatable({x=x,y=y}, Point)
end

function Point:magnitude()
  return math.sqrt(self.x^2 + self.y^2)
end

local p = Point.new(3,4)
print(p:magnitude())   -- 5.0
print(p.type)          -- 2D Point (from class)

รูปแบบตัวสร้าง

ฟังก์ชัน new() คือตัวสร้าง ซึ่งสร้างตารางที่มีข้อมูลของอินสแตนซ์ แล้วส่งคืนตารางนั้นโดยห่อหุ้มด้วยเมตาเทเบิลที่ชี้ไปยังคลาส นี่เป็นวิธีมาตรฐานในการสร้างออบเจ็กต์ใน Lua

local Circle = {}
Circle.__index = Circle

function Circle.new(cx, cy, radius)
  assert(radius > 0, "radius must be positive")
  return setmetatable({cx=cx, cy=cy, r=radius}, Circle)
end

function Circle:area()
  return math.pi * self.r^2
end

function Circle:perimeter()
  return 2 * math.pi * self.r
end

local c = Circle.new(0, 0, 5)
print(string.format("Area: %.2f", c:area()))

ไวยากรณ์เมธอดเทียบกับฟังก์ชัน

obj:method() เป็นรูปแบบย่อของ obj.method(obj) กำหนดเมธอดด้วยไวยากรณ์โคลอน (function Cls:method()) เพื่อรับ self โดยอัตโนมัติ เรียกด้วยโคลอนเพื่อส่งอินสแตนซ์ไปด้วย การใช้จุดและโคลอนปะปนกันอาจทำให้เกิดข้อผิดพลาดที่สังเกตได้ยาก

local Dog = {}
Dog.__index = Dog

-- Define with colon: self is implicit
function Dog:bark(times)
  for i = 1, (times or 1) do
    print(self.name .. ": Woof!")
  end
end

function Dog.new(name)
  return setmetatable({name=name}, Dog)
end

local d = Dog.new("Buddy")
d:bark(2)        -- Buddy: Woof! (x2)
-- Dog.bark(d,1) -- same thing, explicit self

ฟิลด์ระดับคลาสเทียบกับระดับอินสแตนซ์

ฟิลด์ในตารางคลาสจะใช้ร่วมกันโดยทุกอินสแตนซ์ (ตัวแปรคลาส) ส่วนฟิลด์ในตารางอินสแตนซ์จะเป็นของแต่ละอินสแตนซ์ อินสแตนซ์สามารถบดบังฟิลด์ของคลาสได้ด้วยการสร้างฟิลด์ของตัวเองที่ใช้ชื่อเดียวกัน

local Entity = {}
Entity.__index = Entity
Entity.count = 0    -- class-level counter

function Entity.new(name)
  Entity.count = Entity.count + 1
  return setmetatable({name=name, id=Entity.count}, Entity)
end

local a = Entity.new("alpha")
local b = Entity.new("beta")
local c = Entity.new("gamma")

print(Entity.count)  -- 3
print(a.id, b.id, c.id)  -- 1  2  3

tostring สำหรับคลาส

เพิ่ม __tostring ลงในตารางคลาสเพื่อให้ผลลัพธ์การพิมพ์อ่านได้ง่าย เนื่องจากเมตาเทเบิลของอินสแตนซ์คือคลาส และคลาสมี __tostring อินสแตนซ์ทั้งหมดจึงใช้สิ่งนี้โดยอัตโนมัติ

local Vec2 = {}
Vec2.__index = Vec2
Vec2.__tostring = function(v)
  return string.format("Vec2(%g, %g)", v.x, v.y)
end

function Vec2.new(x,y)
  return setmetatable({x=x,y=y}, Vec2)
end

function Vec2.__add(a, b)
  return Vec2.new(a.x+b.x, a.y+b.y)
end

local v1 = Vec2.new(1,2)
local v2 = Vec2.new(3,4)
print(v1+v2)   -- Vec2(4, 6)

การตรวจสอบประเภทอินสแตนซ์

ตรวจสอบว่าออบเจ็กต์เป็นอินสแตนซ์ของคลาสหรือไม่ โดยเปรียบเทียบเมตาเทเบิลของออบเจ็กต์กับตารางคลาส นี่คือสิ่งที่เทียบเท่ากับ instanceof ใน Lua

local Dog = {}
Dog.__index = Dog

function Dog.new(name)
  return setmetatable({name=name}, Dog)
end

local function isDog(obj)
  return getmetatable(obj) == Dog
end

local d = Dog.new("Rex")
local t = {}
print(isDog(d))  -- true
print(isDog(t))  -- false

เมธอดส่วนตัว

เมธอดส่วนตัวคือฟังก์ชันภายในไฟล์โมดูล ไม่สามารถเรียกจากภายนอกได้ แต่เมธอดสาธารณะของโมดูลสามารถเข้าถึงได้ในฐานะค่าจากขอบเขตภายนอก

local Account = {}
Account.__index = Account

-- Private helper
local function validate(amount)
  return type(amount)=="number" and amount > 0
end

function Account.new(balance)
  return setmetatable({balance=balance or 0}, Account)
end

function Account:deposit(amount)
  assert(validate(amount), "invalid amount")
  self.balance = self.balance + amount
end

function Account:getBalance() return self.balance end

การเปรียบเทียบคลาส

โอเวอร์โหลด __eq และ __lt เพื่อกำหนดการเทียบเท่าและการเรียงลำดับแบบกำหนดเอง Lua จะเรียก __eq สำหรับตารางก็ต่อเมื่อตัวถูกดำเนินการทั้งสองมีเมตาเทเบิลเดียวกัน

local Temp = {}
Temp.__index = Temp
Temp.__eq = function(a,b) return a.celsius == b.celsius end
Temp.__lt = function(a,b) return a.celsius < b.celsius end
Temp.__tostring = function(t)
  return t.celsius.."°C"
end

function Temp.new(c)
  return setmetatable({celsius=c}, Temp)
end

local t1 = Temp.new(100)
local t2 = Temp.new(0)
print(t1 == Temp.new(100))  -- true
print(t2 < t1)              -- true

หลายคลาส

แต่ละคลาสเป็นตารางอิสระที่มีเมตาเทเบิลของตัวเอง ออบเจ็กต์จากคนละคลาสจึงมีเมตาเทเบิลต่างกัน นี่คือพื้นฐานของระบบการเขียนโปรแกรมเชิงวัตถุหลายคลาสใน Lua

local Cat = {}
Cat.__index = Cat

function Cat.new(name) return setmetatable({name=name,lives=9},Cat) end
function Cat:loseLife() self.lives=self.lives-1; return self.lives end

local Dog2 = {}
Dog2.__index = Dog2
function Dog2.new(name) return setmetatable({name=name,tricks={}},Dog2) end
function Dog2:learn(t) self.tricks[#self.tricks+1]=t end

local c = Cat.new("Whiskers")
local d = Dog2.new("Buddy")
d:learn("sit"); d:learn("stay")
print(c:loseLife(), #d.tricks)  -- 8  2

ตรวจสอบความเข้าใจอย่างรวดเร็ว

เหตุใดเราจึงตั้งค่า ClassName.__index = ClassName?

สรุป: คลาสผ่านเมตาเทเบิล

สรุป:

  • คลาส = ตาราง + __index = self
  • ตัวสร้าง: function Cls.new(...) return setmetatable({}, Cls) end
  • เมธอด: กำหนดในตารางคลาสและเรียกด้วยไวยากรณ์โคลอน
  • ฟิลด์คลาสเทียบกับฟิลด์อินสแตนซ์: ฟิลด์คลาสใช้ร่วมกัน ส่วนฟิลด์อินสแตนซ์เป็นของแต่ละออบเจ็กต์
  • ตรวจสอบประเภท: getmetatable(obj) == Cls

คำถามที่พบบ่อย

บทเรียน “คลาสผ่านเมทาเทเบิล” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “คลาสผ่านเมทาเทเบิล” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “คลาสผ่านเมทาเทเบิล”

จำลองคลาสด้วยตารางและ __index เพื่อค้นหาเมธอด คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “คลาสผ่านเมทาเทเบิล” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม

ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. คลาสผ่านเมทาเทเบิล
  2. ตัวสร้างและ new()
  3. เมธอดของอินสแตนซ์และ self
  4. การห่อหุ้มด้วยคลอเชอร์
← กลับไปที่ Lua Academy