Lua イテレーター


イテレータは、標準テンプレート ライブラリ コンテナ内の一部またはすべての要素をトラバースするために使用できるオブジェクトです。各イテレータ オブジェクトは、コンテナ内の特定のアドレスを表します。

Lua では、イテレータはポインタ型構造をサポートする一種です。コレクションの各要素を横断できます。


イテレータのジェネリック

ジェネリックは、それ自体の中に反復関数を保存します。実際には、反復関数、状態定数、制御変数の 3 つの値が保存されます。

イテレーターのジェネリックは、コレクションのキーと値のペアを提供します。 構文形式は次のとおりです。

for k, v in pairs(t) do
    print(k, v)
end

上記のコードでは、k、v は変数リストであり、pair(t) は式リストです。

次の例を参照してください:

array = {"Lua", "Tutorial"}

for key,value in ipairs(array) 
do
   print(key, value)
end

上記のコード実行の出力結果は次のとおりです:

1  Lua
2  Tutorial

上記の例では、Lua がデフォルトで提供する反復関数 ipairs を使用しました。

normative for の実行プロセスを見てみましょう:

  • まず、in の後ろにある式の値を初期化して計算します。式は、normative for で必要な 3 つの値を返す必要があります: 反復関数、状態定数、および制御変数 ; 複数値の代入と同様に、式によって返される結果の数が 3 未満の場合、自動的に nil で埋められ、超過部分は無視されます。

  • 2 番目に、状態定数と制御変数をパラメーターとして使用して反復関数を呼び出します (注: for 構造体の場合、状態定数は役に立ちません。初期化中に値を取得して反復関数に渡すだけです)。

  • 3 番目に、反復関数によって返された値を変数リストに代入します。

  • 4 番目に、返された最初の値が nil の場合、ループは終了します。それ以外の場合は、ループ本体が実行されます。

  • 5番目に、2番目のステップに戻り、繰り返し関数を再度呼び出します

。 Lua では、関数を使用してイテレータを記述することがよくあります。関数が呼び出されるたびに、コレクションの次の要素が返されます。 Lua のイテレータには次の 2 つのタイプがあります:

  • ステートレスイテレータ

  • マルチステートイテレータ


ステートレスイテレータ

ステートレスイテレータは、ステートフルイテレータを保持しないことを意味するため、ループ内でステートレスを使用できますイテレータを使用して、クロージャ作成の追加コストを回避します。

各反復では、2 つの変数 (状態定数と制御変数) の値をパラメーターとして使用して反復関数が呼び出されます。ステートレス反復子は、次の要素を取得するためにこれら 2 つの値のみを使用します。

この種のステートレス反復子の典型的な単純な例は、配列の各要素を走査する ipairs です。

次の例では、単純な関数を使用して、数値 n の 2 乗を実現する反復子を実装します。

function square(iteratorMaxCount,currentNumber)
   if currentNumber<iteratorMaxCount
   then
      currentNumber = currentNumber+1
   return currentNumber, currentNumber*currentNumber
   end
end

for i,n in square,3,0
do
   print(i,n)
end

上記の例の出力結果は次のとおりです:

1	1
2	4
3	9

反復された状態には、走査されているテーブル (それはループ中は変化しません) 状態定数) と現在のインデックスの添字 (制御変数)、ipairs および反復関数は非常に単純なので、次のように Lua で実装できます:

function iter (a, i)
    i = i + 1
    local v = a[i]
    if v then
       return i, v
    end
end
 
function ipairs (a)
    return iter, a, 0
end

Lua が ipairs(a) を呼び出してループを開始すると、反復関数 iter、状態定数 a、制御変数の初期値 0 の 3 つの値が取得され、Lua は iter(a,0) を呼び出して 1,a[1 を返します。 ] ( a[1]=nil でない場合); 2 番目の反復では iter(a,1) を呼び出し、最初の nil 要素まで 2、a[2]... を返します。


複数状態イテレータ

多くの場合、イテレータは単純な状態定数や制御変数の代わりに複数の状態情報を保存する必要があります。最も簡単な方法はクロージャを使用することであり、別の方法はすべての状態を結合することです。情報はカプセル化されます。この場合、テーブルにテーブルが使用され、すべての情報をテーブルに格納できるため、通常、反復関数には 2 番目のパラメーターが必要ありません。


次の例では独自のイテレータを作成しました:

array = {"Lua", "Tutorial"}

function elementIterator (collection)
   local index = 0
   local count = #collection
   -- 闭包函数
   return function ()
      index = index + 1
      if index <= count
      then
         --  返回迭代器的当前元素
         return collection[index]
      end
   end
end

for element in elementIterator(array)
do
   print(element)
end

上記の例の出力結果は次のとおりです:

Lua
Tutorial

上記の例では、セットを計算するために elementIterator でクロージャー関数が使用されていることがわかります。各要素のサイズを指定して出力します。