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


2.5 – テーブル

テーブル型は連想配列を実装します。連想配列とは、数値だけでなく、文字列や、nil以外の言語の任意の他の値でもインデックスできる配列です。さらに、テーブルには固定サイズがありません。テーブルにいくらでも要素を動的に追加できます。テーブルはLuaにおける主要な(実際には唯一の)データ構造メカニズムであり、強力なものです。テーブルを使って、通常の配列、シンボルテーブル、集合、レコード、キュー、その他のデータ構造を、単純で統一的、かつ効率的な方法で表現します。Luaはテーブルをパッケージの表現にも使用します。例えば、io.readと書くとき、それは「ioパッケージのreadエントリ」を意味します。Luaにとっては、それは「文字列"read"をキーとしてテーブルioにインデックスする」という意味になります。

Luaのテーブルは、値でも変数でもなく、オブジェクトです。JavaやSchemeの配列に慣れていれば、その意味するところがおおよそ理解できるでしょう。しかし、CやPascalの配列の考え方しか知らない場合は、少し視野を広げる必要があります。テーブルは動的に割り当てられるオブジェクトと考えることができます。プログラムはテーブルへの参照(またはポインタ)のみを操作します。背後で隠れたコピーや新しいテーブルの作成は行われません。さらに、Luaでテーブルを宣言する必要はありません。実際、テーブルを宣言する方法はありません。テーブルは、最も単純な形式では{}と書かれるコンストラクタ式によって作成します。

    a = {}     -- create a table and store its reference in `a'
    k = "x"
    a[k] = 10        -- new entry, with key="x" and value=10
    a[20] = "great"  -- new entry, with key=20 and value="great"
    print(a["x"])    --> 10
    k = 20
    print(a[k])      --> "great"
    a["x"] = a["x"] + 1     -- increments entry "x"
    print(a["x"])    --> 11
テーブルは常に匿名です。テーブルを保持する変数とテーブル自体との間に固定された関係はありません。
    a = {}
    a["x"] = 10
    b = a      -- `b' refers to the same table as `a'
    print(b["x"])  --> 10
    b["x"] = 20
    print(a["x"])  --> 20
    a = nil    -- now only `b' still refers to the table
    b = nil    -- now there are no references left to the table
プログラムにテーブルへの参照が残っていない場合、Luaのメモリ管理は最終的にテーブルを削除し、そのメモリを再利用します。

各テーブルは、異なる型のインデックスを持つ値を格納でき、新しいエントリを格納する必要に応じて拡張します。

    a = {}     -- empty table
    -- create 1000 new entries
    for i=1,1000 do a[i] = i*2 end
    print(a[9])    --> 18
    a["x"] = 10
    print(a["x"])  --> 10
    print(a["y"])  --> nil
最後の行に注目してください。グローバル変数と同様に、テーブルフィールドは初期化されていない場合はnilに評価されます。また、グローバル変数と同様に、テーブルフィールドにnilを代入して削除できます。これは偶然ではありません。Luaはグローバル変数を通常のテーブルに格納します。この件については、第14章で詳しく説明します。

レコードを表現するには、フィールド名をインデックスとして使用します。Luaは、a.namea["name"]の糖衣構文として提供することにより、この表現をサポートしています。したがって、前の例の最後の行をよりクリーンな方法で記述できます。

    a.x = 10                    -- same as a["x"] = 10
    print(a.x)                  -- same as print(a["x"])
    print(a.y)                  -- same as print(a["y"])
Luaにとって、2つの形式は同等であり、自由に混在させることができます。しかし、人間の読者にとっては、それぞれの形式が異なる意図を示している場合があります。

初心者がよく犯す間違いは、a.xa[x]を混同することです。最初の形式はa["x"]、つまり文字列"x"でインデックスされたテーブルを表します。2番目の形式は、変数xの値でインデックスされたテーブルです。違いを見てください。

    a = {}
    x = "y"
    a[x] = 10                 -- put 10 in field "y"
    print(a[x])   --> 10      -- value of field "y"
    print(a.x)    --> nil     -- value of field "x" (undefined)
    print(a.y)    --> 10      -- value of field "y"

従来の配列を表現するには、整数のキーを持つテーブルを使用します。サイズを宣言する方法はありません。必要な要素を初期化するだけです。

    -- read 10 lines storing them in a table
    a = {}
    for i=1,10 do
      a[i] = io.read()
    end
配列の要素を反復処理するとき、最初に初期化されていないインデックスはnilになります。この値を配列の末尾を表す番兵として使用できます。たとえば、最後の例で読み取った行を次のコードで出力できます。
    -- print the lines
    for i,line in ipairs(a) do
      print(line)
    end
基本的なLuaライブラリは、ipairsを提供します。これは、配列の最初のnil要素で配列が終わるという規約に従って、配列の要素を反復処理できる便利な関数です。

任意の値をテーブルのインデックスにできるため、配列のインデックスを任意の数値で開始できます。ただし、Luaでは、(Cのようにゼロではなく)1から配列を開始するのが一般的であり、標準ライブラリはこの規約に従います。

任意の型でテーブルにインデックスを付けることができるため、テーブルにインデックスを付けるとき、等価性で発生するのと同じ微妙な問題が発生します。数値の0と文字列の"0"の両方でテーブルにインデックスを付けることができますが、これら2つの値は(等価性によると)異なり、したがってテーブル内の異なる位置を示します。同様に、文字列"+1""01"、および"1"はすべて異なる位置を示します。インデックスの実際の型について疑問がある場合は、明示的な変換を使用して確認してください。

    i = 10; j = "10"; k = "+10"
    a = {}
    a[i] = "one value"
    a[j] = "another value"
    a[k] = "yet another value"
    print(a[j])            --> another value
    print(a[k])            --> yet another value
    print(a[tonumber(j)])  --> one value
    print(a[tonumber(k)])  --> one value
この点に注意しないと、プログラムに微妙なバグが発生する可能性があります。