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

ตัวสร้างและ new()

เขียนฟังก์ชันตัวสร้างที่สร้างและกำหนดค่าเริ่มต้นให้อินสแตนซ์

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

หน้าที่ของตัวสร้าง

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

local Player = {}
Player.__index = Player

function Player.new(name, hp, mp)
  assert(type(name)=="string" and name~="","need name")
  return setmetatable({
    name = name,
    hp   = hp or 100,
    mp   = mp or 50,
    alive = true,
    items = {},
  }, Player)
end

local p = Player.new("Hero")
print(p.name, p.hp, p.mp)  -- Hero  100  50

ตัวสร้างแบบต่อคำสั่ง

ตัวสร้างแบบต่อคำสั่งจะส่งคืน self จากเมธอดกำหนดค่า ทำให้สามารถเรียกเมธอดต่อกันระหว่างการสร้างได้ นี่คือรูปแบบตัวสร้างใน Lua

local Config = {}
Config.__index = Config

function Config.new()
  return setmetatable({_data={}}, Config)
end

function Config:set(k,v) self._data[k]=v; return self end
function Config:build() return self._data end

local cfg = Config.new()
  :set("host","localhost")
  :set("port",8080)
  :set("debug",true)
  :build()

print(cfg.host, cfg.port)

ตัวสร้างแบบคัดลอก

ตัวสร้างแบบคัดลอกจะสร้างอินสแตนซ์ใหม่ที่มีค่าเดียวกับอินสแตนซ์เดิม สิ่งสำคัญคือ ให้ใช้การคัดลอกแบบตื้นหรือแบบลึกตามความต้องการว่าตารางซ้อนกันควรใช้ร่วมกันหรือแยกเป็นอิสระ

local function deepCopy(orig)
  if type(orig)~="table" then return orig end
  local copy = {}
  for k,v in pairs(orig) do copy[deepCopy(k)]=deepCopy(v) end
  return setmetatable(copy, getmetatable(orig))
end

local Item = {}
Item.__index = Item

function Item.new(name, stats)
  return setmetatable({name=name, stats=stats or {}}, Item)
end

function Item:clone()
  return deepCopy(self)
end

local sword = Item.new("Sword",{damage=50})
local clone = sword:clone()
clone.stats.damage = 30
print(sword.stats.damage)  -- 50 (unchanged)

ตัวสร้างพร้อมการตรวจสอบ

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

local Rectangle = {}
Rectangle.__index = Rectangle

function Rectangle.new(w, h)
  assert(type(w)=="number" and w>0,"width must be positive number")
  assert(type(h)=="number" and h>0,"height must be positive number")
  return setmetatable({width=w, height=h}, Rectangle)
end

function Rectangle:area() return self.width * self.height end
function Rectangle:perimeter() return 2*(self.width+self.height) end

local r = Rectangle.new(5, 3)
print(r:area(), r:perimeter())  -- 15  16

รูปแบบค่าเริ่มต้น

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

local Sprite = {}
Sprite.__index = Sprite

local DEFAULTS = {x=0,y=0,rotation=0,scale=1,visible=true,alpha=1}

function Sprite.new(image, opts)
  local cfg = opts or {}
  local self = {image=image}
  for k,v in pairs(DEFAULTS) do
    self[k] = cfg[k] ~= nil and cfg[k] or v
  end
  return setmetatable(self, Sprite)
end

local s = Sprite.new("hero.png",{x=100,y=200})
print(s.x,s.y,s.scale)  -- 100 200 1

เมธอดโรงงานแบบสแตติก

คลาสหนึ่งสามารถมีเมธอดโรงงานหลายรายการสำหรับสถานการณ์การสร้างที่แตกต่างกัน วิธีนี้สะอาดกว่าการยัดพารามิเตอร์ที่ไม่บังคับจำนวนมากไว้ในตัวสร้างเพียงตัวเดียว

local Color = {}
Color.__index = Color

function Color.fromRGB(r,g,b)
  return setmetatable({r=r,g=g,b=b}, Color)
end

function Color.fromHex(hex)
  hex = hex:gsub("#","")
  return setmetatable({
    r=tonumber(hex:sub(1,2),16),
    g=tonumber(hex:sub(3,4),16),
    b=tonumber(hex:sub(5,6),16),
  }, Color)
end

function Color:toHex()
  return string.format("#%02X%02X%02X",self.r,self.g,self.b)
end

local red = Color.fromHex("#FF0000")
print(red:toHex())  -- #FF0000

ทะเบียนตัวสร้าง

ใช้ทะเบียนเพื่อติดตามอินสแตนซ์ทั้งหมด วิธีนี้ทำให้ดำเนินการกับวัตถุทั่วทั้งระบบได้ เช่น "ทำลายทั้งหมด" หรือวนซ้ำผ่านวัตถุทุกตัวของชนิดหนึ่ง

local Enemy = {}
Enemy.__index = Enemy
Enemy._all = {}

function Enemy.new(name, hp)
  local self = setmetatable({name=name, hp=hp}, Enemy)
  Enemy._all[#Enemy._all+1] = self
  return self
end

function Enemy.destroyAll()
  for _, e in ipairs(Enemy._all) do
    print("Destroying:", e.name)
  end
  Enemy._all = {}
end

Enemy.new("Goblin",30)
Enemy.new("Orc",80)
print("Count:", #Enemy._all)  -- 2
Enemy.destroyAll()

การเริ่มต้นแบบขี้เกียจ

ฟิลด์บางรายการใช้เวลาคำนวณมาก ให้ใช้ __index ร่วมกับฟังก์ชันเพื่อคำนวณและเก็บแคชเมื่อมีการเข้าถึงครั้งแรก

local BigData = {}
BigData.__index = function(t, k)
  if k == "processed" then
    print("Computing processed...")
    local result = {}
    for i,v in ipairs(rawget(t,"raw")) do result[i]=v*2 end
    rawset(t,"processed",result)
    return result
  end
end

function BigData.new(raw)
  return setmetatable({raw=raw}, BigData)
end

local d = BigData.new({1,2,3,4,5})
print(d.processed[3])  -- Computing...  6
print(d.processed[3])  -- 6 (cached, no recompute)

สร้างต้นแบบจากอินสแตนซ์

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

local Unit = {}
Unit.__index = Unit

function Unit.new(t)
  return setmetatable({name=t.name,hp=t.hp,atk=t.atk}, Unit)
end

function Unit:clone()
  return Unit.new({name=self.name,hp=self.hp,atk=self.atk})
end

function Unit:__tostring()
  return self.name.."(HP:"..self.hp..",ATK:"..self.atk..")"
end

local template = Unit.new({name="Soldier",hp=100,atk=10})
local u1 = template:clone(); u1.name="Alpha"
local u2 = template:clone(); u2.name="Beta"
print(tostring(u1),tostring(u2))

ความปลอดภัยของข้อผิดพลาดในตัวสร้าง

หากการสร้างล้มเหลวระหว่างทาง (เช่น การจัดสรรทรัพยากร) ต้องตรวจสอบให้แน่ใจว่าไม่มีวัตถุที่สร้างไม่สมบูรณ์หลุดออกไป ใช้ pcall เพื่อดักจับข้อผิดพลาดระหว่างการสร้างและล้างทรัพยากรเมื่อจำเป็น

local FileHandle = {}
FileHandle.__index = FileHandle

function FileHandle.new(path, mode)
  local f, err = io.open(path, mode or "r")
  if not f then
    return nil, "cannot open " .. path .. ": " .. err
  end
  return setmetatable({_f=f, path=path}, FileHandle)
end

function FileHandle:read(fmt) return self._f:read(fmt) end
function FileHandle:close() self._f:close() end

local fh, err = FileHandle.new("data.txt")
if not fh then print("Error:", err)
else print(fh:read("l")); fh:close()
end

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

ตัวสร้าง (new()) มีหน้าที่อะไรใน OOP ของ Lua

สรุป: ตัวสร้าง

สรุป:

  • ตัวสร้างตรวจสอบค่า เริ่มต้นการทำงาน และเรียก setmetatable
  • ใช้ตารางค่าเริ่มต้นเพื่อจัดการพารามิเตอร์ที่ไม่บังคับอย่างเป็นระเบียบ
  • ใช้เมธอดโรงงานหลายรายการสำหรับสถานการณ์การสร้างที่แตกต่างกัน
  • ใช้ตัวสร้างแบบโคลนสำหรับวัตถุแม่แบบ
  • ใช้การเริ่มต้นแบบขี้เกียจผ่าน __index สำหรับฟิลด์ที่ใช้เวลาคำนวณมาก
  • เมื่อล้มเหลว (เช่น การจัดสรรทรัพยากร) ให้ตัวสร้างส่งคืน nil+err

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

บทเรียน “ตัวสร้างและ new()” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ตัวสร้างและ new()”

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

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

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

บทเรียน “ตัวสร้างและ new()” ใช้เวลานานแค่ไหน

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

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

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

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

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