Pattern e buone pratiche per i moduli
Utilizzi il pattern local M = {} ed esponga in modo ordinato l'API pubblica.
Pattern e buone pratiche per i moduli è una lezione Lua Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Lua Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Lua Academy include 4 lezioni in totale.
Il modello M = {}
Il modello universale per i moduli Lua: dichiarare una tabella locale, popolarla e restituirla. Tutti i simboli pubblici vengono inseriti in M; tutti gli helper privati sono semplici variabili locali. È chiaro, minimale e funziona ovunque.
-- 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 MModulo autoreferenziale
All'interno di un modulo, le funzioni possono chiamare altre funzioni del modulo tramite il nome (M.foo()) oppure come variabili locali. L'uso delle variabili locali è leggermente più veloce; l'uso di M.foo() consente agli utenti di sovrascrivere M.foo e di fare in modo che la chiamata interna utilizzi la sovrascrittura (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 MModello Singleton
Un modulo può comportarsi come un singleton: possiede uno stato interno mutabile condiviso da tutti gli utenti. Poiché require memorizza il modulo nella cache, tutte le chiamate a require("mod") ricevono lo stesso oggetto con lo stesso stato.
-- 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:Modulo come spazio dei nomi
Usi un modulo esclusivamente come spazio dei nomi per evitare di inquinare la tabella globale. Raggruppi costanti e utility correlate sotto un unico nome, come un package negli altri linguaggi.
-- 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 ...Modulo factory
Un modulo che esporta una funzione factory invece di una semplice tabella. La factory crea e restituisce nuove istanze con il proprio stato privato. Questo è il modello delle classi applicato a livello di modulo.
-- 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 MFunzione di inizializzazione del modulo
Alcuni moduli richiedono una configurazione prima dell'uso. Fornisca una funzione M.init(config) che memorizzi la configurazione nello stato privato del modulo. Questo consente l'iniezione delle dipendenze e facilita i test.
-- 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 MModulo immutabile
Impedisca agli utenti di modificare accidentalmente l'API del modulo usando __newindex per bloccare tutte le scritture. È particolarmente utile per i moduli di libreria, nei quali il monkey patching accidentale potrebbe causare malfunzionamenti.
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)Documentazione con LDoc
Una convenzione comune per documentare i moduli Lua consiste nell'usare commenti in stile LDoc con il prefisso ---. Sebbene il linguaggio non li imponga, questi commenti consentono agli strumenti di generazione della documentazione di produrre automaticamente la documentazione dell'API.
--- 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 MTest dei moduli
Testi un modulo richiedendolo e verificando ogni funzione. Usi un semplice test runner oppure busted (il framework di test per Lua). Mantenga i test in un file separato che rispecchi il percorso del modulo.
-- 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)Composizione dei moduli
I sistemi complessi combinano più moduli. Un punto di ingresso principale richiede e collega i sottomoduli. Questa separazione delle responsabilità mantiene ogni modulo focalizzato e testabile in modo indipendente.
-- 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()Verifica rapida
Qual è lo scopo principale del modello di modulo local M = {} ... return M?
Riepilogo: buone pratiche per i moduli
Riepilogo:
- Usi sempre
local M = {} ... return M - Privato = variabili locali a livello di file; pubblico = campi di M
- Il require memorizza nella cache l'istanza del singleton
- Usi funzioni factory per lo stato specifico di ogni istanza
- Blocchi le modifiche ai moduli con __newindex
- Esegua i test in file separati; documenti il codice con commenti ---
Impara Lua con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 40
- Lezioni
- 159
Domande Frequenti
La lezione «Pattern e buone pratiche per i moduli» è gratuita?
Sì — il testo completo di «Pattern e buone pratiche per i moduli» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Lua Academy, passa a CoddyKit PRO. Il corso Lua Academy include 4 lezioni in totale.
Cosa imparerò in «Pattern e buone pratiche per i moduli»?
Utilizzi il pattern local M = {} ed esponga in modo ordinato l'API pubblica. Eserciti Lua Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Lua Academy?
Non è richiesta alcuna esperienza precedente. Lua Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Pattern e buone pratiche per i moduli»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Lua Academy?
Sì. Ogni lezione Lua Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- La funzione require
- Scrittura di un file di modulo
- package.path e package.cpath
- Pattern e buone pratiche per i moduli