この初版は Lua 5.0 向けに書かれています。その後のバージョンでも大部分は関連がありますが、いくつか違いがあります。
第 4 版は Lua 5.3 を対象にしており、Amazon やその他の書店でご利用いただけます。
この本を購入することで、Lua プロジェクトを支援することもできます。


17.3 - デフォルト値を持つテーブルの再検討

第 13.4.3 節で、非 nil のデフォルト値を持つテーブルを実装する方法について論じました。具体的な手法を 1 つ取り上げ、他の 2 つの手法は弱参照テーブルを必要とするので後回しにしています。今こそそのテーマを見直す時です。後でわかるように、デフォルト値のそれらの 2 つの手法は、ここで見た 2 つの一般的な手法、オブジェクト属性とメモ化の具体的な応用です。

最初のソリューションでは、弱参照テーブルを使用して、各テーブルにそのデフォルト値を関連付けます

    local defaults = {}
    setmetatable(defaults, {__mode = "k"})
    local mt = {__index = function (t) return defaults[t] end}
    function setDefault (t, d)
      defaults[t] = d
      setmetatable(t, mt)
    end
defaults に weak キーがない場合、デフォルト値を持つすべてのテーブルが永続的な存在に固定されます。

2 番目のソリューションでは、異なるデフォルト値に異なるメタテーブルを使用しますが、デフォルト値を繰り返す場合は同じメタテーブルを再利用します。これは、メモ化の代表的な使用方法です

    local metas = {}
    setmetatable(metas, {__mode = "v"})
    function setDefault (t, d)
      local mt = metas[d]
      if mt == nil then
        mt = {__index = function () return d end}
        metas[d] = mt     -- memoize
      end
      setmetatable(t, mt)
    end
この場合、使用されなくなったメタテーブルの収集を許可するために弱参照値を使用します。

デフォルト値のこれらの 2 つの実装を考えると、どちらが最善ですか? いつものように、それは状況次第です。どちらも複雑さは似ており、パフォーマンスも似ています。1 番目の実装では、デフォルト値を持つ各テーブルに対して少しの単語が必要になります (defaults 内のエントリ)。2 番目の実装では、異なるデフォルト値ごとに数十の単語が必要になります (新しいテーブル、新しいクロージャー、metas 内のエントリ)。したがって、アプリケーションに少数の異なるデフォルト値を持つ何千ものテーブルがある場合、2 番目の実装は明らかに優れています。一方、共通のデフォルトを共有するテーブルがほとんどない場合は、1 番目の実装を使用する必要があります。