Lua Academy · Oppitunti

Moduulien rakenteet ja parhaat käytännöt

Käyttäkää local M = {} -rakennetta ja tuokaa julkinen API selkeästi esiin.

Oppitunti 4/412 vaihetta

Moduulien rakenteet ja parhaat käytännöt on ilmainen Lua Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Lua Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Lua Academy-kurssilla on yhteensä 4 oppituntia.

Malli M = {}

Yleispätevä Lua-moduulien malli: määritelkää paikallinen taulukko, täyttäkää se ja palauttakaa se. Kaikki julkiset symbolit sijoitetaan taulukkoon M; kaikki yksityiset apufunktiot ovat tavallisia paikallisia muuttujia. Tämä malli on selkeä, minimaalinen ja toimii kaikkialla.

-- 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

Itseensä viittaava moduuli

Moduulin sisällä funktiot voivat kutsua muita moduulin funktioita joko nimen avulla (M.foo()) tai paikallisina muuttujina. Paikallisten muuttujien käyttö on hieman nopeampaa; M.foo()-kutsun käyttö mahdollistaa sen, että käyttäjät voivat korvata M.foo-funktion ja sisäinen kutsu käyttää korvaavaa versiota (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

Singleton-malli

Moduuli voi toimia singletonina: sillä on muuttuva sisäinen tila, jonka kaikki kutsujat jakavat. Koska require tallentaa moduulin välimuistiin, kaikki require("mod")-kutsut saavat saman olion ja saman tilan.

-- 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:

Moduuli nimiavaruutena

Käyttäkää moduulia pelkkänä nimiavaruutena, jotta globaali taulukko ei täyty ylimääräisistä nimistä. Ryhmitelkää toisiinsa liittyvät vakiot ja apuohjelmat yhden nimen alle muiden kielten paketin tapaan.

-- 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 ...

Tehdasmoduuli

Tehdasmoduuli vie tavallisen taulukon sijaan tehdasfunktion. Tehdas luo ja palauttaa uusia instansseja, joilla on oma yksityinen tilansa. Tämä on luokkamalli moduulitasolla.

-- 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

Moduulin init-funktio

Jotkin moduulit tarvitsevat määritykset ennen käyttöä. Tarjotkaa M.init(config)-funktio, joka tallentaa määritykset moduulin yksityiseen tilaan. Tämä mahdollistaa riippuvuuksien injektoinnin ja testattavuuden.

-- 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

Muuttumaton moduuli

Estäkää käyttäjiä muuttamasta moduulin ohjelmointirajapintaa vahingossa käyttämällä __newindex-metametodia kaikkien kirjoitusyritysten estämiseen. Tämä on erityisen hyödyllistä kirjastoissa, joissa vahingossa tehty monkey patching voisi rikkoa toiminnallisuuden.

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)

Dokumentointi LDocilla

Lua-moduulien dokumentoinnissa käytetään yleisesti LDoc-tyylisiä kommentteja, joiden etuliite on ---. Vaikka kieli ei pakota käyttämään niitä, kommenttien avulla dokumentointityökalut voivat tuottaa ohjelmointirajapinnan dokumentaation automaattisesti.

--- 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

Moduulien testaaminen

Testatkaa moduulia lataamalla se require-kutsulla ja suorittamalla jokainen sen funktio. Käyttäkää yksinkertaista testiajo-ohjelmaa tai bustedia (Lua-testikehystä). Pitäkää testit erillisessä tiedostossa, joka vastaa moduulin polkua.

-- 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)

Moduulien yhdistäminen

Monimutkaiset järjestelmät koostetaan useista moduuleista. Pääsisäänkäynti lataa alimoduulit require-kutsuilla ja yhdistää ne toisiinsa. Tämä vastuiden erottelu pitää kunkin moduulin selkeänä ja itsenäisesti testattavana.

-- 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()

Pikatarkistus

Mikä on local M = {} ... return M-moduulimallin päätarkoitus?

Kertaus: moduulien parhaat käytännöt

Yhteenveto:

  • Käyttäkää aina mallia local M = {} ... return M
  • Yksityiset = tiedostotason paikalliset muuttujat; julkiset = M:n kentät
  • Singletonissa require tallentaa moduuli-instanssin välimuistiin
  • Käyttäkää tehdasfunktioita instanssikohtaista tilaa varten
  • Jäädyttäkää moduulit __newindex-metametodilla muutosten estämiseksi
  • Testatkaa erillisissä tiedostoissa ja dokumentoikaa ----kommenteilla
Aloita maksutta

Opi Lua tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
40
Oppitunnit
159

Usein kysytyt kysymykset

Onko oppitunti ”Moduulien rakenteet ja parhaat käytännöt” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Lua Academy-oppimispolun 3 oppituntia, myös oppitunnin “Moduulien rakenteet ja parhaat käytännöt”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Lua Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Moduulien rakenteet ja parhaat käytännöt”?

Käyttäkää local M = {} -rakennetta ja tuokaa julkinen API selkeästi esiin. Harjoittelet Lua Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Lua Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Lua Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Moduulien rakenteet ja parhaat käytännöt”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Lua Academy-oppitunnilla?

Kyllä. Jokainen Lua Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. require-funktio
  2. Moduulitiedoston kirjoittaminen
  3. package.path ja package.cpath
  4. Moduulien rakenteet ja parhaat käytännöt
← Takaisin: Lua Academy