この初版は Lua 5.0 向けに執筆されました。依然として後のバージョンでも大部分が関連性がありますが、相違点があります。
第 4 版は Lua 5.3 版を対象にしており、Amazon やその他の書店で購入できます。
本を購入することで、Lua プロジェクトを支援することもできます。


13.4.1 – __index メタメソッド

テーブル内の欠落したフィールドにアクセスすると結果は nil になると前述しました。これは事実ですが、すべてではありません。実際、こうしたアクセスによって、インタプリタは __index メタメソッドの検索がトリガされます。通常どおりそのようなメソッドがなければ、アクセス結果は nil になります。それ以外の場合は、メタメソッドが結果を提供します。

典型的な例は継承です。ウィンドウを説明する複数のテーブルを作成したいとします。それぞれのテーブルは、位置、大きさ、配色などのいくつかのウィンドウ パラメータを説明している必要があります。こうしたすべてのパラメータには既定値があるため、既定値以外のウィンドウ オブジェクトを作成してパラメータを提供する必要があります。最初の選択肢は、欠落したフィールドを埋めるコンストラクタを提供することです。2 番目の選択肢は、新しいウィンドウに対してプロトタイプ ウィンドウからどの欠落したフィールドでも 継承 できるようにすることです。まず、プロトタイプと、メタテーブルを共有する新しいウィンドウを作成するコンストラクタ関数を宣言します

    -- create a namespace
    Window = {}
    -- create the prototype with default values
    Window.prototype = {x=0, y=0, width=100, height=100, }
    -- create a metatable
    Window.mt = {}
    -- declare the constructor function
    function Window.new (o)
      setmetatable(o, Window.mt)
      return o
    end
次に、__index メタメソッドを定義します
    Window.mt.__index = function (table, key)
      return Window.prototype[key]
    end
このコードの後で、新しいウィンドウを作成し、欠落したフィールドをクエリします
    w = Window.new{x=10, y=20}
    print(w.width)    --> 100
Lua が w に要求したフィールドがないものの、__index フィールドがあるメタテーブルがあることを検出すると、Lua はこの __index メタメソッドを、引数 w (テーブル) と "width" (欠落したキー) を使用して呼び出します。このメタメソッドにより、プロトタイプは指定されたキーでインデックスが作成され、結果が返されます。

継承の __index メタメソッドの使用方法は一般的であるため、Lua はショートカットを提供しています。名前にもかかわらず、__index メタメソッドは関数の必要はありません。その代わりにテーブルになることもできます。それが関数である場合、Lua はそれらをテーブルと、その引数として欠落したキーを呼び出します。それがテーブルである場合、Lua はそのテーブルにアクセスし直します。したがって、前の例では __index を単に以下のように宣言できます

    Window.mt.__index = Window.prototype
この時点で、Lua がメタテーブルの __index フィールドを探す時、その値が Window.prototype のテーブルであることを検出します。その結果、Lua はこのテーブルへのアクセスを繰り返します。つまり、以下と同等の操作を行います。
    Window.prototype["width"]
これは目的の結果を提供します。

テーブルを __index メタメソッドとして使用すると、単一継承を実装するための安価でシンプルな方法になります。関数はコストは高くなりますが、より多くの柔軟性を提供します。多重継承、キャッシング、その他多くのバリエーションを実装できます。これらの継承形式については 第 16 章 で説明します。

__index メタメソッドを呼び出さずにテーブルにアクセスする場合は、rawget 関数を使用します。rawget(t,i) の呼び出しはテーブル t へのローアクセスを行います。ローアクセスを行うことでコードが高速化することはありません(関数呼び出しのオーバーヘッドにより、得られる利得はすべてなくなります)。しかし、後述するように、場合によっては必要な場合があります。