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

การเขียนไฟล์มอดูล

สร้างมอดูลโดยส่งคืนตารางฟังก์ชันจากไฟล์ .lua

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

รูปแบบโมดูลพื้นฐาน

รูปแบบโมดูลมาตรฐานของ Lua คือสร้างตาราง local ชื่อ M เพิ่มฟังก์ชันและค่าเข้าไป แล้วส่งคืนตารางนั้นในตอนท้าย ตารางนี้คือ API สาธารณะของโมดูล ส่วนตัวแปร local อื่น ๆ ในไฟล์จะเป็นข้อมูลส่วนตัวทั้งหมด

-- stringutils.lua
local M = {}

function M.trim(s)
  return s:match("^%s*(.-)%s*$")
end

function M.split(s, sep)
  local t = {}
  for p in s:gmatch("[^"..sep.."]+") do t[#t+1]=p end
  return t
end

return M

-- Usage:
-- local su = require("stringutils")
-- print(su.trim("  hello  "))

สถานะส่วนตัว

ตัวแปรที่ประกาศเป็น local ในไฟล์โมดูลจะเป็นข้อมูลส่วนตัว ผู้เรียกใช้ไม่สามารถเข้าถึงได้ ฟังก์ชันในโมดูลสามารถเข้าถึงสถานะส่วนตัวในฐานะ upvalue ได้ นี่คือกลไกการห่อหุ้มข้อมูลของ Lua

-- counter.lua
local M = {}
local count = 0   -- private state

function M.increment(n)
  count = count + (n or 1)
end

function M.reset()
  count = 0
end

function M.get()
  return count
end

return M

โมดูลที่มีการเริ่มต้นการทำงาน

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

-- cache.lua
local M = {}
local store = {}   -- initialized at load time
local hits = 0
local misses = 0

function M.get(key)
  if store[key] ~= nil then
    hits = hits + 1
    return store[key]
  end
  misses = misses + 1
  return nil
end

function M.set(key, val) store[key] = val end
function M.stats() return {hits=hits, misses=misses} end

return M

โมดูลที่มีคลาส

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

-- point.lua
local Point = {}
Point.__index = Point

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

function Point:distance(other)
  local dx, dy = self.x-other.x, self.y-other.y
  return math.sqrt(dx*dx + dy*dy)
end

function Point:__tostring()
  return string.format("(%g,%g)", self.x, self.y)
end

return Point

-- Usage:
-- local Point = require("point")
-- local p = Point.new(3, 4)

ค่าคงที่ของโมดูล

ส่งออกค่าคงที่โดยเพิ่มค่าเหล่านั้นลงในตารางโมดูล ตามธรรมเนียมแล้ว ค่าคงที่จะใช้ตัวพิมพ์ใหญ่ เนื่องจาก Lua ไม่มี const ผู้ใช้จึงสามารถแก้ไขค่าเหล่านี้ได้ในทางเทคนิค แต่การตั้งชื่อด้วยตัวพิมพ์ใหญ่สื่อว่า “อย่าแก้ไข”

-- colors.lua
local M = {}

M.RED   = {r=255, g=0,   b=0}
M.GREEN = {r=0,   g=255, b=0}
M.BLUE  = {r=0,   g=0,   b=255}
M.WHITE = {r=255, g=255, b=255}
M.BLACK = {r=0,   g=0,   b=0}

function M.toHex(c)
  return string.format("#%02X%02X%02X", c.r, c.g, c.b)
end

return M

การกำหนดเวอร์ชันของโมดูล

ใส่ฟิลด์เวอร์ชันไว้ในโมดูล ผู้เรียกใช้สามารถตรวจสอบเวอร์ชันเพื่อให้แน่ใจว่าเข้ากันได้ ควรใช้การกำหนดเวอร์ชันตามความหมาย (major.minor.patch)

-- mylib.lua
local M = {}
M._VERSION = "1.2.3"
M._NAME = "mylib"
M._DESCRIPTION = "My Lua library"

function M.hello(name)
  return "Hello, " .. (name or "World") .. "!"
end

return M

-- Usage:
local mylib = require("mylib")
print(mylib._VERSION)   -- 1.2.3
print(mylib.hello("Lua"))

โมดูลย่อย

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

-- mylib/init.lua  (loaded by require("mylib"))
local M = {}

M.strings = require("mylib.strings")
M.tables  = require("mylib.tables")
M.math    = require("mylib.math")

M._VERSION = "2.0.0"

return M

-- Users can require the whole library:
-- local mylib = require("mylib")
-- mylib.strings.trim(...)

-- Or individual sub-modules:
-- local strs = require("mylib.strings")

โมดูลที่มีเมตาเทเบิล

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

-- format.lua
local M = {}
setmetatable(M, {__call = function(_, fmt, ...)
  return string.format(fmt, ...)
end})

function M.pad(s, width, char)
  char = char or " "
  return string.rep(char, math.max(0, width - #s)) .. s
end

return M

-- Usage:
-- local fmt = require("format")
-- print(fmt("%.2f", 3.14))   -- 3.14
-- print(fmt.pad("42", 5))    --    42

การโหลดโมดูลย่อยแบบล่าช้า

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

-- biglib.lua
local M = {}
local submodules = {"strings", "tables", "math", "io"}

setmetatable(M, {
  __index = function(t, k)
    for _, name in ipairs(submodules) do
      if name == k then
        local mod = require("biglib." .. k)
        rawset(t, k, mod)
        return mod
      end
    end
    return nil
  end
})

return M

-- Loads biglib.strings only when accessed:
-- local lib = require("biglib")
-- lib.strings.trim(...)

รูปแบบการทดสอบโมดูล

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

-- utils.lua
local M = {}

function M.clamp(v, lo, hi)
  return math.max(lo, math.min(hi, v))
end

-- Self-test: only runs when executed directly
if debug.getinfo(2, "S") == nil then
  -- Running as main script, not required
  print("Testing clamp...")
  assert(M.clamp(5, 0, 10) == 5)
  assert(M.clamp(-1, 0, 10) == 0)
  assert(M.clamp(15, 0, 10) == 10)
  print("All tests passed!")
end

return M

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

วิธีมาตรฐานในการกำหนดสถานะส่วนตัวในโมดูล Lua คืออะไร

สรุป: การเขียนโมดูล

สรุป:

  • รูปแบบ: local M = {} ... return M
  • ตัวแปร local ในไฟล์ = ข้อมูลส่วนตัว ฟิลด์ของ M = API สาธารณะ
  • โค้ดระดับโมดูลทำงานหนึ่งครั้งเมื่อมีการเรียกใช้ครั้งแรก
  • ส่งออกคลาสผ่านฟังก์ชันสร้างออบเจ็กต์ในตารางโมดูล
  • โหลดโมดูลย่อยแบบล่าช้าผ่าน __index
  • ใส่ _VERSION เพื่อใช้ตรวจสอบความเข้ากันได้

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

บทเรียน “การเขียนไฟล์มอดูล” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การเขียนไฟล์มอดูล”

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

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

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

บทเรียน “การเขียนไฟล์มอดูล” ใช้เวลานานแค่ไหน

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

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

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

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

  1. ฟังก์ชัน require
  2. การเขียนไฟล์มอดูล
  3. package.path และ package.cpath
  4. รูปแบบมอดูลและแนวทางปฏิบัติที่ดี
← กลับไปที่ Lua Academy