Lua Academy · Lektion

Modulmönster och bästa praxis

Använd mönstret local M = {} och exponera ett offentligt API på ett tydligt sätt.

Lektion 4 av 412 steg

Modulmönster och bästa praxis är en gratis lektion i Lua Academy på CoddyKit. Detta är lektion 4 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Lua Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Lua Academy innehåller totalt 4 lektioner.

Mönstret M = {}

Det universella Lua-mönstret för moduler: deklarera en lokal tabell, fyll den med innehåll och returnera den. Alla publika symboler läggs i M; alla privata hjälpfunktioner är vanliga lokala variabler. Detta är tydligt, minimalt och fungerar överallt.

-- The canonical module pattern
local M = {}

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

-- Public API
function M.sqrt(x)
  assert(validate(x), "expected non-negative number")
  return math.sqrt(x)
end

M.PI = math.pi

return M

Självrefererande modul

Inuti en modul kan funktioner anropa andra modulfunktioner antingen via namn (M.foo()) eller som lokala funktioner. Lokala funktioner är något snabbare; med M.foo() kan användare skriva över M.foo och få det interna anropet att använda ersättningen (monkey patching).

local M = {}

-- Option A: use M.foo inside (allows override)
function M.double(n) return M.multiply(n, 2) end
function M.multiply(a, b) return a * b end

-- Option B: use local function (faster, no override)
local function mul(a, b) return a * b end
function M.triple(n) return mul(n, 3) end

return M

Singletonmönstret

En modul kan fungera som en singleton: den har ett förändringsbart internt tillstånd som delas av alla anropare. Eftersom require cachelagrar modulen får alla anrop av require("mod") samma objekt med samma tillstånd.

-- config.lua (singleton)
local M = {}
local _config = {env="dev", logLevel="info"}

function M.set(key, val)
  _config[key] = val
end

function M.get(key)
  return _config[key]
end

function M.load(t)
  for k,v in pairs(t) do _config[k]=v end
end

return M

-- All callers share the same config:

Modul som namnrymd

Använd en modul enbart som namnrymd för att undvika att förorena den globala tabellen. Gruppera relaterade konstanter och hjälpverktyg under ett namn, ungefär som ett paket i andra språk.

-- constants.lua
local M = {
  HTTP = {
    OK=200, CREATED=201, NO_CONTENT=204,
    BAD_REQUEST=400, UNAUTHORIZED=401,
    NOT_FOUND=404, SERVER_ERROR=500,
  },
  COLORS = {RED="#FF0000", GREEN="#00FF00", BLUE="#0000FF"},
  MAX_RETRIES = 3,
  TIMEOUT_SEC = 30,
}
return M

-- local C = require("constants")
-- if status == C.HTTP.NOT_FOUND then ...

Fabrikmodul

En modul som exporterar en fabriksfunktion i stället för en vanlig tabell. Fabriken skapar och returnerar nya instanser med eget privat tillstånd. Detta är klassmönstret på modulnivå.

-- logger.lua
local M = {}

function M.new(name, level)
  level = level or "info"
  local levels = {debug=1,info=2,warn=3,error=4}
  local self = {}
  
  function self.log(msgLevel, msg)
    if levels[msgLevel] >= levels[level] then
      print(string.format("[%s][%s] %s", name, msgLevel:upper(), msg))
    end
  end
  
  function self.info(msg)  self.log("info",  msg) end
  function self.warn(msg)  self.log("warn",  msg) end
  function self.error(msg) self.log("error", msg) end
  
  return self
end

return M

Modulens initieringsfunktion

Vissa moduler kräver konfiguration innan de kan användas. Tillhandahåll en funktion M.init(config) som lagrar konfigurationen i modulens privata tillstånd. Detta möjliggör beroendeinjektion och testbarhet.

-- db.lua
local M = {}
local pool = nil

function M.init(config)
  pool = {
    host = config.host or "localhost",
    port = config.port or 5432,
    connections = {},
  }
  print("DB initialized:", pool.host, pool.port)
end

function M.query(sql)
  assert(pool, "call db.init() first")
  -- ... execute query
  return {}
end

return M

Oföränderlig modul

Förhindra att användare av misstag ändrar modulens API genom att använda __newindex för att blockera alla skrivningar. Detta är särskilt användbart för biblioteksmoduler där oavsiktlig monkey patching kan orsaka problem.

local function freeze(t)
  return setmetatable({}, {
    __index = t,
    __newindex = function(_, k, _)
      error("module is read-only, cannot set: " .. tostring(k), 2)
    end
  })
end

local M = {}
function M.add(a, b) return a + b end
function M.sub(a, b) return a - b end

return freeze(M)

Dokumentera med LDoc

En vanlig konvention för att dokumentera Lua-moduler är kommentarer i LDoc-stil med prefixet ---. Även om språket inte kräver detta kan kommentarerna göra det möjligt för verktyg för dokumentationsgenerering att automatiskt skapa API-dokumentation.

--- A utility module for string operations.
-- @module stringutils
local M = {}

--- Trim leading and trailing whitespace.
-- @param s string The input string.
-- @return string The trimmed string.
function M.trim(s)
  return s:match("^%s*(.-)%s*$")
end

--- Count occurrences of a substring.
-- @param str string The string to search.
-- @param sub string The substring to count.
-- @return number Count of occurrences.
function M.count(str, sub)
  local _, n = str:gsub(sub, "")
  return n
end

return M

Testa moduler

Testa en modul genom att kräva den och köra varje funktion. Använd en enkel testrunner eller busted (testramverket för Lua). Förvara testerna i en separat fil som speglar modulens sökväg.

-- test/test_stringutils.lua
local su = require("stringutils")

local function test(name, fn)
  local ok, err = pcall(fn)
  if ok then print("[PASS] " .. name)
  else   print("[FAIL] " .. name .. ": " .. err)
  end
end

test("trim removes spaces", function()
  assert(su.trim("  hello  ") == "hello")
end)

test("trim empty string", function()
  assert(su.trim("") == "")
end)

test("count occurrences", function()
  assert(su.count("banana", "a") == 3)
end)

Sammansätta moduler

Komplexa system sätts samman av flera moduler. En huvudingång kräver och kopplar samman undermodulerna. Denna ansvarsfördelning håller varje modul fokuserad och möjliggör oberoende testning.

-- app.lua (main entry point)
local config = require("config")
local db     = require("db")
local server = require("server")

-- Configure from environment
config.load({
  dbHost = os.getenv("DB_HOST") or "localhost",
  port   = tonumber(os.getenv("PORT")) or 8080,
})

-- Wire modules together
db.init({host=config.get("dbHost"), port=5432})
server.init({port=config.get("port"), db=db})
server.start()

Snabbkontroll

Vad är huvudsyftet med modulmönstret local M = {} ... return M?

Sammanfattning: bästa praxis för moduler

Sammanfattning:

  • Använd alltid local M = {} ... return M
  • Privat = lokala variabler på filnivå; publikt = M-fält
  • Singleton: require cachelagrar modulinstansen
  • Använd fabriksfunktioner för tillstånd per instans
  • Frys moduler med __newindex för att förhindra ändringar
  • Testa i separata filer; dokumentera med ---- kommentarer
Gratis att börja

Lär dig Lua med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
40
Lektioner
159

Vanliga frågor

Är lektionen ”Modulmönster och bästa praxis” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Lua Academy, inklusive ”Modulmönster och bästa praxis”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Lua Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Modulmönster och bästa praxis”?

Använd mönstret local M = {} och exponera ett offentligt API på ett tydligt sätt. Ni övar på Lua Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Lua Academy?

Du behöver inga förkunskaper. Utbildningen i Lua Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Modulmönster och bästa praxis”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Lua Academy-lektionen?

Ja. Varje Lua Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Funktionen require
  2. Skriva en modulfilsfil
  3. package.path och package.cpath
  4. Modulmönster och bästa praxis
← Tillbaka till Lua Academy