アットウィキロゴ

クロージャ

クロージャ(Closure)とは、「関数」と「その関数が作成された環境(外部ローカル変数)」をセットにしたものです。
簡単に言うと、関数が定義された場所のローカル変数を、その関数の実行が終了した後も「記憶」してアクセスできる機能を指します。


概要

Playdateのメイン開発言語であるLuaにおいて、クロージャ(Closure)は非常に強力で頻繁に使われる概念です。
Playdate SDKを利用する際、特にメニュー操作、タイマーアニメーションコールバック関数などで無意識のうちに使っていることも多いでしょう。
1. クロージャとは何か?
クロージャを一言で言うと、「自分が定義された時の環境(ローカル変数など)を、後から実行される時まで覚えておくことができる関数」のことです。
Luaの関数は「第一級オブジェクト」であり、変数に代入したり引数として渡したりできます。その際、その関数内で参照している外側のローカル変数(Upvalueと呼ばれます)も一緒にパッケージ化されて保持されます。
2. Playdate SDKでの代表的な活用例
A. システムメニューの登録
Playdateのシステムメニュー(Aボタンで出すメニュー)に項目を追加する際、項目ごとに異なる動作をさせたい場合にクロージャが便利です。
local function setupMenu()
    local clickCount = 0 -- この変数がクロージャに保持される
 
    playdate.getSystemMenu():addMenuItem("Check Count", function()
        clickCount += 1
        print("メニューが呼ばれた回数: " .. clickCount)
    end)
end
 
setupMenu()
この例では、setupMenu 関数が終わった後も、メニューのコールバック関数は clickCount という変数を保持し続け、実行されるたびにカウントを増やせます。
:B. タイマーのコールバック (playdate.timer)
特定の時間が経過した後に処理を行いたい場合、その時点での状態をクロージャに閉じ込めて渡すことができます。
local function spawnEnemy(x, y)
    local enemy = { name = "Ghost", x = x, y = y }
 
    -- 2秒後に敵を消滅させる
    playdate.timer.performAfterDelay(2000, function()
        print(enemy.name .. " を座標(" .. enemy.x .. ")で消滅させました")
    end)
end
performAfterDelay に渡した関数は、2秒後でも enemy 変数にアクセス可能です。

3. 実践的なテクニック:関数を作る関数(ファクトリ)
複数の似たような動作をするオブジェクトを作る際に、共通の変数を隠蔽(カプセル化)するのに役立ちます。
-- 「特定のスピードで移動する関数」を生成する
local function createMover(speed)
    local distance = 0 -- 内部状態
    return function()
        distance += speed
        return distance
    end
end
 
local slowMover = createMover(1)
local fastMover = createMover(5)
 
print(slowMover()) -- 1
print(fastMover()) -- 5
print(slowMover()) -- 2
 

4. Playdate開発における注意点
クロージャは非常に便利ですが、Playdateのようなリソースの限られたハードウェアでは以下の点に注意が必要です。
:メモリとガベージコレクション (GC)
  • 生成のタイミング: playdate.update() の中で毎フレーム function() ... end とクロージャを生成すると、毎フレーム新しいメモリが割り当てられ、ガベージコレクションの負荷が高まって処理落ち(カクつき)の原因になります
  • 対策: 頻繁に呼び出される場所では、クロージャを事前に定義して再利用するか、必要以上に大きな変数をキャプチャしないようにします
メモリリークの可能性
クロージャが外側の大きなテーブルやオブジェクトを参照している場合、そのクロージャが生きている限り、参照されているオブジェクトもメモリから解放されません。
タイマーなどが終了した後は、参照を適切に切る(nilを代入するなど)意識を持つと安全です。

まとめ
特徴 Playdateでのメリット
状態の保持 グローバル変数を使わずに、特定の処理専用の変数を維持できる
簡潔な記述 コールバック関数をその場で定義できるため、コードの見通しが良くなる
柔軟性 playdate.timer や playdate.frameTimer と組み合わせて、複雑な非同期処理が書ける
Playdate開発において、クロージャは「一時的な状態を、後で実行される処理に安全に受け渡すためのカプセル」だと考えると理解しやすいでしょう。

関連ページ

最終更新:2026年04月30日 10:15