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

เมธอดของอินสแตนซ์และ self

กำหนดเมธอดด้วยไวยากรณ์โคลอนและพารามิเตอร์ self โดยนัย

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

self คืออินสแตนซ์

เมื่อคุณเรียก obj:method() Lua จะส่ง obj เป็นอาร์กิวเมนต์ตัวแรกโดยอัตโนมัติ ตามธรรมเนียมแล้วพารามิเตอร์นี้จะชื่อ self เมธอดใช้ self เพื่อเข้าถึงข้อมูลของอินสแตนซ์และเรียกเมธอดอื่น

local Counter = {}
Counter.__index = Counter

function Counter.new(start)
  return setmetatable({value=start or 0, step=1}, Counter)
end

function Counter:increment()
  self.value = self.value + self.step
end

function Counter:getValue() return self.value end

local c = Counter.new(10)
c:increment(); c:increment()
print(c:getValue())  -- 12

การเรียกเมธอดต่อกัน

ส่งคืน self จากเมธอดเพื่อให้เรียกต่อกันได้: obj:method1():method2():method3() การเรียกแต่ละครั้งส่งคืนวัตถุเดิม จึงเขียนในรูปแบบต่อคำสั่งได้ วิธีนี้เหมาะที่สุดกับเมธอดที่แก้ไขสถานะ

local Builder = {}
Builder.__index = Builder

function Builder.new()
  return setmetatable({parts={}},Builder)
end

function Builder:add(s) self.parts[#self.parts+1]=s; return self end
function Builder:addAll(t)
  for _,v in ipairs(t) do self.parts[#self.parts+1]=v end
  return self
end
function Builder:build() return table.concat(self.parts," ") end

local result = Builder.new()
  :add("Hello")
  :add("from")
  :addAll({"Lua","OOP"})
  :build()
print(result)  -- Hello from Lua OOP

การเรียกเมธอดอื่น

เมธอดสามารถเรียกเมธอดอื่นของอินสแตนซ์เดียวกันผ่าน self:otherMethod() ซึ่งช่วยนำโค้ดกลับมาใช้ซ้ำภายในคลาสได้ ฟังก์ชันช่วยเหลือส่วนตัวสามารถเป็นฟังก์ชันท้องถิ่นทั่วไปที่รับ self อย่างชัดเจน

local Stack = {}
Stack.__index = Stack

function Stack.new() return setmetatable({_data={},_size=0},Stack) end
function Stack:push(v) self._size=self._size+1; self._data[self._size]=v end
function Stack:pop()
  if self:isEmpty() then return nil end
  local v=self._data[self._size]; self._data[self._size]=nil
  self._size=self._size-1; return v
end
function Stack:peek()
  return not self:isEmpty() and self._data[self._size] or nil
end
function Stack:isEmpty() return self._size==0 end
function Stack:size() return self._size end

local s=Stack.new(); s:push(1);s:push(2);s:push(3)
print(s:pop(),s:peek(),s:size())  -- 3  2  2

คำเตือนเรื่องการเขียนทับเมธอด

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

local Dog = {}
Dog.__index = Dog
function Dog.new(n) return setmetatable({name=n},Dog) end
function Dog:speak() print(self.name..": Woof!") end

local d = Dog.new("Rex")
d:speak()        -- Rex: Woof!

-- Accidental shadow:
d.speak = "loud"  -- now d.speak is a string, not a function
local ok,err = pcall(function() d:speak() end)
print(ok, err)   -- false  attempt to call a string value

self ในฟังก์ชันเรียกกลับ

การส่งเมธอดไปเป็นฟังก์ชันเรียกกลับจะทำให้ self ที่ส่งโดยอัตโนมัติหายไป ให้ห่อเมธอดไว้ในคลอเชอร์เพื่อเก็บ self ไว้

local Timer = {}
Timer.__index = Timer
function Timer.new(n) return setmetatable({count=n},Timer) end
function Timer:tick()
  self.count=self.count-1
  print("Ticking, count:", self.count)
end

local t = Timer.new(3)

-- Wrong: loses self
-- local cb = t.tick  -- cb(t) works but cb() doesn't

-- Correct: closure captures self
local cb = function() t:tick() end
cb(); cb(); cb()  -- Ticking 3 times

เมธอดสแตติกกับเมธอดของอินสแตนซ์

เมธอดสแตติกถูกเรียกบนคลาส ไม่ใช่อินสแตนซ์ เมธอดนี้ไม่มี self (หรืออาจได้รับคลาสเป็น self) ใน Lua ไม่มีความแตกต่างอย่างเป็นทางการ โดยธรรมเนียมให้ใช้ . (ไม่ใช่ :) กับเมธอดสแตติก

local MathUtils = {}
MathUtils.__index = MathUtils

-- Static method (no instance needed)
function MathUtils.clamp(v, lo, hi)
  return math.max(lo, math.min(hi, v))
end

-- Instance method (needs self)
function MathUtils:scale(factor)
  self.value = self.value * factor
end

print(MathUtils.clamp(15, 0, 10))  -- 10
local m = setmetatable({value=5},MathUtils)
m:scale(3)
print(m.value)  -- 15

เมธอดมิกซ์อิน

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

local Serializable = {}
function Serializable:serialize()
  local parts={}
  for k,v in pairs(self) do
    if type(v)~="function" then
      parts[#parts+1]=k.."="..tostring(v)
    end
  end
  return "{"..table.concat(parts,",").."}"
end

local User = {}
User.__index = User
User.serialize = Serializable.serialize   -- mixin!

function User.new(n,a) return setmetatable({name=n,age=a},User) end

local u = User.new("Alice",30)
print(u:serialize())

เมธอดนามธรรม

Lua ไม่ได้บังคับใช้เมธอดนามธรรม แต่คุณสามารถกำหนดเมธอดของคลาสพื้นฐานให้โยนข้อผิดพลาด เพื่อบังคับให้คลาสย่อยเขียนทับเมธอดนั้นได้ นี่เป็นธรรมเนียมที่สื่อว่า "ต้องเขียนทับ"

local Shape = {}
Shape.__index = Shape

function Shape.new() return setmetatable({},Shape) end

function Shape:area()
  error(type(self).." must implement area()",2)
end

function Shape:describe()
  print("Shape area:", self:area())
end

local sq={}
setmetatable(sq,{__index=Shape})
function sq:area() return 4*4 end

sq:describe()  -- Shape area: 16

ตารางเมธอด

สำหรับคลาสที่มีเมธอดจำนวนมาก ให้จัดกลุ่มเมธอดตามหน้าที่ เมธอดทั้งหมดในตารางเดียวกันจะใช้การค้นหาเมตาเทเบิลร่วมกัน แต่คุณสามารถแบ่งตามขอบเขตความรับผิดชอบโดยใช้เนมสเปซย่อย

local Entity = {}
Entity.__index = Entity

Entity.Physics = {}
function Entity.Physics:applyForce(fx,fy)
  self.vx=(self.vx or 0)+fx
  self.vy=(self.vy or 0)+fy
end

Entity.Render = {}
function Entity.Render:draw()
  print(string.format("Draw at (%g,%g)",self.x or 0,self.y or 0))
end

-- Mix into main class
for k,v in pairs(Entity.Physics) do Entity[k]=v end
for k,v in pairs(Entity.Render) do Entity[k]=v end

function Entity.new(x,y) return setmetatable({x=x,y=y},Entity) end
local e=Entity.new(10,20); e:draw(); e:applyForce(5,0); print(e.vx)

การมอบหมายกับการสืบทอด

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

local Logger = {}
Logger.__index = Logger
function Logger.new(name) return setmetatable({name=name},Logger) end
function Logger:log(msg) print("["..self.name.."] "..msg) end

local Service = {}
Service.__index = Service

function Service.new(name)
  return setmetatable({
    name=name,
    logger=Logger.new(name)  -- delegation
  },Service)
end

function Service:start()
  self.logger:log("starting...")  -- delegate logging
  print(self.name, "running")
end

Service.new("AuthService"):start()

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

obj:method() และ obj.method() แตกต่างกันอย่างไร

สรุป: เมธอดของอินสแตนซ์

สรุป:

  • ไวยากรณ์การเรียกด้วยโคลอน: obj:method() == obj.method(obj)
  • ส่งคืน self เพื่อให้เรียกเมธอดต่อกันได้
  • เรียกเมธอดอื่น: self:otherMethod()
  • ฟังก์ชันเรียกกลับ: ห่อไว้ในคลอเชอร์เพื่อรักษา self
  • เมธอดสแตติก: โดยธรรมเนียมให้ใช้สัญกรณ์จุด
  • เลือกการมอบหมายแทนการสืบทอดที่ลึกเพื่อความยืดหยุ่น

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

บทเรียน “เมธอดของอินสแตนซ์และ self” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “เมธอดของอินสแตนซ์และ self”

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

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

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

บทเรียน “เมธอดของอินสแตนซ์และ self” ใช้เวลานานแค่ไหน

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

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

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

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

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