0Pricing
Lua Academy · レッスン

モジュールファイルの作成

.luaファイルから関数のテーブルを返してモジュールを作成します。

「モジュールファイルの作成」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。

基本的なモジュールパターン

Lua の標準的なモジュールパターンは、ローカルテーブル M を作成し、そこに関数や値を追加して、最後に返す方法です。このテーブルがモジュールの公開 API になります。ファイル内のその他のローカル変数はすべて非公開です。

-- 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 として宣言した変数は非公開であり、呼び出し側からアクセスできません。モジュール内の関数は、アップバリューとして非公開の状態にアクセスできます。これは 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() 関数に記述してください。モジュールレベルの方法は最初に require されたときに 1 回実行されますが、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

クラスを持つモジュール

モジュールはクラスをエクスポートできます。クラスはコンストラクター関数を持つテーブルです。返されるモジュールテーブルには 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"))

サブモジュール

大規模なライブラリはサブモジュールに分割します。メインモジュールでサブモジュールを require して再エクスポートすることも、それぞれのサブモジュールを独立して使うこともできます。モジュールパスに対応するディレクトリ構成でファイルを整理してください。

-- 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
  • ファイル内のローカル変数=非公開、M のフィールド=公開 API
  • モジュールレベルのコードは最初の require 時に 1 回実行されます
  • モジュールテーブル内のコンストラクターを使ってクラスをエクスポートします
  • __index によってサブモジュールを遅延読み込みします
  • 互換性確認のために _VERSION を含めます

よくある質問

「モジュールファイルの作成」レッスンは無料ですか?

はい。「モジュールファイルの作成」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。

「モジュールファイルの作成」で何を学びますか?

.luaファイルから関数のテーブルを返してモジュールを作成します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Lua Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「モジュールファイルの作成」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLua Academyレッスンでコードを書いて実行できますか?

はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. require関数
  2. モジュールファイルの作成
  3. package.pathとpackage.cpath
  4. モジュールのパターンとベストプラクティス
← Lua Academyに戻る