この初版は Lua 5.0 用に書かれました。後からリリースされたバージョンでも大部分は依然として関連性がありますが、 いくつか違いがあります。
第 4 版は Lua 5.3 をターゲットにしており、 Amazon や他の書店で購入できます。
この本を購入することで、 Lua プロジェクトをサポートすることもできます。


3.6 - テーブルコンストラクタ

コンストラクタとは、テーブルを作成して初期化する式のことです。Lua だけの独特の機能で、最も用途が広く汎用性の高いメカニズムの 1 つです。

最も単純なコンストラクタは空のコンストラクタ {} で、空のテーブルを作成します。これは前に見ました。コンストラクタは配列(とも呼ばれる)も初期化します。第 11 章シーケンス または リスト)。たとえば、以下のステートメントは

    days = {"Sunday", "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday"}
days[1] を "日曜日" という文字列で初期化し(最初の要素のインデックスは 0 ではなく常に 1 です)、days[2] を "月曜日" で初期化します。
    print(days[4])  --> Wednesday

コンストラクタに定数式のみを使用する必要はありません。各要素の値には、あらゆる種類の式を使用できます。たとえば、次のようにして短い正弦テーブルを作成できます。

    tab = {sin(1), sin(2), sin(3), sin(4),
           sin(5), sin(6), sin(7), sin(8)}

テーブルをレコードとして使用するように初期化するために、Lua では次のような構文が提供されています。

    a = {x=0, y=0}
これは次と同じです。
    a = {}; a.x=0; a.y=0

テーブルの作成にどのコンストラクタを使用しても、他のフィールドをいつでも追加したり、削除したりできます。

    w = {x=0, y=0, label="console"}
    x = {sin(0), sin(1), sin(2)}
    w[1] = "another field"
    x.f = w
    print(w["x"])   --> 0
    print(w[1])     --> another field
    print(x.f[1])   --> another field
    w.x = nil       -- remove field "x"
つまり、すべてのテーブルは同じように作成されます。コンストラクタは初期化にのみ影響します。

Lua がコンストラクタを評価するたびに、新しいテーブルが作成されて初期化されます。その結果、テーブルを使用してリンクリストを実装できます。

    list = nil
    for line in io.lines() do
      list = {next=list, value=line}
    end
このコードは標準入力から行を読み込み、リンクリストに格納します。逆順です。リスト内の各ノードは、2 つのフィールドを持つテーブルです。value は行の内容で、next は次のノードへの参照です。次のコードはリストの内容を出力します。
    l = list
    while l do
      print(l.value)
      l = l.next
    end
(リストをスタックとして実装したため、行は逆順に出力されます) わかりやすいとはいえ、実際の Lua プログラムではこの実装はほとんど使用しません。リストは配列として実装した方がよいです。これは第 11 章で説明します。

同じコンストラクタにレコードスタイルとリストスタイルの初期化を混在させることができます。

    polyline = {color="blue", thickness=2, npoints=4,
                 {x=0,   y=0},
                 {x=-10, y=0},
                 {x=-10, y=1},
                 {x=0,   y=1}
               }
上記の例は、より複雑なデータ構造を表すためにどのようにコンストラクタをネストできるかも示しています。各要素 polyline[1]polyline[4] はレコードを表すテーブルです。
    print(polyline[2].x)    --> -10

この 2 つのコンストラクタ形式には限界があります。たとえば、負のインデックスや、適切な識別子でない文字列インデックスを持つフィールドを初期化することはできません。このようなニーズのために、より一般化された形式があります。この形式では、初期化するインデックスを明示的に式として角かっこで記述します。

    opnames = {["+"] = "add", ["-"] = "sub",
               ["*"] = "mul", ["/"] = "div"}
    
    i = 20; s = "-"
    a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s}
    
    print(opnames[s])    --> sub
    print(a[22])         --> ---
この構文はより面倒ですが、柔軟性も向上します。リストスタイルとレコードスタイルの両方の形式は、このより一般的な形式の特殊なケースです。コンストラクタ
    {x=0, y=0}
は次と同じです。
    {["x"]=0, ["y"]=0}
コンストラクタも次です。
    {"red", "green", "blue"}
は次と同じです。
    {[1]="red", [2]="green", [3]="blue"}

本当に配列を 0 から開始したい人のために、次のようなものを記述することは難しくありません。

    days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday"}
最初の値、「Sunday」は index 0 にあります。このゼロは他のフィールドには影響しませんが、自然に「Monday」は index 1 になります。それは配列ではそれを作る最初のリスト値だからです。他の値はそれに従います。この機能にもかかわらず、Lua では先頭が 0 の配列を使用することはお勧めしません。ほとんどの関数は配列の先頭インデックスが 1 であると予想します。その結果、こうした配列を正しく処理しません。

最後のエントリの後にカンマを入れることができます。これらの末尾カンマはオプションですが、有効です。

    a = {[1]="red", [2]="green", [3]="blue",}
こうした柔軟性により、Lua テーブルを生成するプログラムの作成が容易になります。最後のエレメントを特別ケースとして扱う必要がないからです。

最後に、コンストラクタのカンマの代わりにセミコロンを使用できます。普通、セミコロンをコンストラクタのセクションを区切ることに使用します。たとえば、リストの部分をレコードの部分から分離するために使用します。

    {x=10, y=45; "one", "two", "three"}