Menu
Coddy logo textTech

読み取り専用テーブル

CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 46/70。

クロージャは真のプライバシーを提供しますが、コンストラクター内でメソッドを定義する必要があります。別の用途には、別のアプローチがあります。それは、作成後にオブジェクトを読み取り専用にすることです。これは、固定点の座標のように、フィールドを表示可能にしつつ変更不可能にしたい場合に便利です。

__newindex metamethod は、テーブルに新しい値を代入しようとする試みをインターセプトします。すべての代入を all ブロックするようにすることで、object を凍結できます。

local ImmutablePoint = {}

function ImmutablePoint.new(x, y)
    local data = {x = x, y = y}
    
    local proxy = {}
    setmetatable(proxy, {
        __index = data,
        __newindex = function()
            error("Cannot modify immutable object")
        end
    })
    
    return proxy
end

秘訣はプロキシテーブルを使うことです。actual データはdataに存在し、ユーザーは空のproxyを操作します。

読み取り時には、__indexdata から取得します。書き込み時には、代わりに __newindex がトリガーされ、これをブロックします。

local p = ImmutablePoint.new(10, 20)
print(p.x)  -- 10(読み取りは動作する)
p.x = 50    -- エラー: 不変オブジェクトは変更できません

このパターンは、configuration object、数学定数、または初期化後に決して変更されるべきでない任意の data に役立ちます。object は完全に読み取り可能なままです。ただし、変更することはできません。

challenge icon

チャレンジ

簡単

ImmutableConfig class を作成して、読み取り専用の設定オブジェクトを生成しましょう!一度作成すると、これらの config オブジェクトでは設定の読み取りはできますが、変更しようとする操作はすべて完全にブロックされます。

コードは次の 2 つのファイルに分けて整理します。

  • ImmutableConfig.lua:凍結された設定オブジェクトを生成する module を作成します。.new(appName, version, maxUsers) function では、これら 3 つの値を internal に保存し、すべての field の読み取りを許可しながら、modifications を防ぐ proxy table を返します。値を変更しようとしたときは、actual な error を発生させる代わりに Error: Config is read-only を Print します。
  • main.lua:ImmutableConfig を実際に動かしてみましょう!config の値として 3 つの inputs を読み取り、config object を作成します。その後、次の操作を行って正しく動作することを示します。
    • 3 つの original の値をすべて Print する
    • maxUsers field の modify を試みる(Error message が発生するはずです)
    • 値が実際には changed されていないことを証明するため、もう一度 maxUsers を Print する

次の 3 つの inputs を受け取ります。

  1. application name(string)
  2. version(string)
  3. maximum users(number)

出力には config の値、modification を試みたときの error、および値が変更されていないことの確認が表示されます。

App: {appName}
Version: {version}
Max Users: {maxUsers}
Error: Config is read-only
Max Users: {maxUsers}

たとえば、inputs が MyApp2.0100 の場合、出力は次のようになります。

App: MyApp
Version: 2.0
Max Users: 100
Error: Config is read-only
Max Users: 100

Remember:proxy pattern では、user が操作する empty table を使用し、actual data は別の internal table に保持されます。__index metamethod は data table から値を取得し、__newindex はあらゆる write の試みを intercept して(そして blocks して)くれます。

自分で試してみよう

-- ImmutableConfig モジュールをインポートする
local ImmutableConfig = require('ImmutableConfig')

-- 入力を読み取る
local appName = io.read()
local version = io.read()
local maxUsers = tonumber(io.read())

-- TODO: ImmutableConfig.new() を使用して config オブジェクトを作成する

-- TODO: 次の形式ですべての3つの元の値を出力する:
-- App: {appName}
-- Version: {version}
-- Max Users: {maxUsers}

-- TODO: maxUsers フィールドを変更しようとする(これによりエラーメッセージがトリガーされるはず)

-- TODO: 変更されていないことを証明するために maxUsers を再度出力する
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Luaオンラインコンパイラ