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


7.2 – ジェネリック for のセマンティクス

これらの従来の反復処理関数の 1 つの欠点は、新しいループごとに新しいクロージャを作成する必要があることです。ほとんどの場合、これはそれほど問題ではありません。たとえば、allwords 反復処理関数では、ファイル全体を読み込むコストに比べて、1 つのクロージャを作成するコストは無視できます。ただし、このオーバーヘッドが好ましくない場合があります。そのような場合は、反復処理の状態を保持するためにジェネリック for 自体を活用できます。

ジェネリック for がループ中に反復処理関数自体を保持していることがわかりました。実際、3 つの値を保持します。反復処理関数、不変状態、および制御変数です。次に詳細を見てみましょう。

ジェネリック for の構文は次のとおりです。

    for <var-list> in <exp-list> do
      <body>
    end
ここで、<var-list> は 1 つ以上の変数名のリストで、コンマで区切られ、<exp-list> は 1 つ以上の式のリストで、やはりコンマで区切られています。式リストは、たいてい 1 つの要素しかなく、反復処理関数ファクトリーの呼び出しです。たとえば、次のコードでは
    for k, v in pairs(t) do
      print(k, v)
    end
変数のリストは k, v ですが、式のリストには単一の要素 pairs(t) があります。多くの場合、変数のリストも変数が 1 つだけで、次のようになります。
    for line in io.lines() do
      io.write(line, '\n')
    end
リストの最初の変数を制御変数と呼びます。この値はループ中は nil になることはありません。これは、nil になるとループが終了するからです。

for が最初にやることは、in の後ろの式を評価することです。これらの式は、for が保持する 3 つの値 (反復処理関数、不変状態、制御変数の初期値) である必要があります。複数の割り当てと同様に、リストの最後 (または最初) の要素のみが 1 つ以上の値になる可能性があり、値の数は 3 に調整されます。余分な値は破棄されるか、必要に応じて nil が追加されます。(単純な反復処理関数を使用する場合、ファクトリーは反復処理関数のみを返すため、不変状態と制御変数は nil を取得します。)

この初期化ステップの後、for は反復処理関数を 2 つの引数 (不変状態と制御変数) で呼び出します。(for 構造では、不変状態にはまったく意味がないことに注意してください。初期化ステップからこの値を取得するだけで、反復処理関数が呼び出されるときに渡されます)。次に、for は反復処理関数によって返された値を変数リストによって宣言された変数に割り当てます。返された最初の値 (制御変数に割り当てられる値) が nil の場合、ループは終了します。それ以外の場合は、for は本体を実行し、反復処理関数を再度呼び出してプロセスを繰り返します。

より正確に言うと、次のような構成は

    for var_1, ..., var_n in explist do block end
次のコードと同等です。
    do
      local _f, _s, _var = explist
      while true do
        local var_1, ... , var_n = _f(_s, _var)
        _var = var_1
        if _var == nil then break end
        block
      end
    end
そのため、反復処理関数が f、不変状態が s、制御変数の初期値が a0 の場合、制御変数は値 a1 = f(s, a0)a2 = f(s, a1) などをループします ainil になるまでです。for に他の変数がある場合、それらは単に f への各呼び出しによって返される追加の値を取得します。