1. ホーム
  2. スクリプト・コラム
  3. ルア

Luaにおけるpairsとipairsの違いのまとめ

2022-01-06 14:22:06

プリアンブル

最近、私は nginx_lua_module モジュールを使って、Header, Body, Cookieに比例してトラフィックを別の場所に転送するようなものを書いています。前のコードを読んだら、ループの中にはpairsを使うものとipairsを使うものがあって、とても混乱した。良い点は、Luaの公式サイトに電子版で Luaでプログラミング 学習するのにとても便利です。以下は、初めてLuaを学習したときのメモと感想ですが、間違っていたら、遠慮なく訂正してください。

その

標準ライブラリは、ファイルの各行を反復処理する(io.ines)、テーブルの要素を反復処理する(pairs)、配列の要素を反復処理する(ipairs)、文字列内の単語を反復処理する(string.gmatch)などの集中型イテレータを提供しています。

pairsとipairsの違い

通常のイテレータは内部で状態(現在の反復位置)を保持していますが、LuaのイテレータはStatelessなので、複数回の反復が可能という利点があります。PythonのIteratorやIterableは、複数回反復する場合、IterableからイテレータIteratorを必要としますが、Luaのイテレータはループ時自体にメンテナンスが必要なのです。

forは反復のたびに、反復対象のステートレスオブジェクトとcontrol引数(反復の状態、1 2 3 ...)の2つの引数でイテレータ関数を呼び出します。

例えば、次のようなループです。

a = {"one", "two", "three"}
for i, v in ipairs(a) do
 print(i, v)
end

まずipairs(a)が実行され、iter関数(LuaはPythonと同様に"ファーストクラス関数"を持つ)、反復処理するオブジェクトa、反復処理開始時の添え字0という三つの値が返されます。そして、最初のforループでiter(a, 0)を呼び出し(上述と同じ引数で)、現在の添え字iとa[i]の値vを返し、forループで定義した変数iとvに代入しているのです。このロジックは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

そうすると、上記のforループ呼び出しのロジックは以下のようになり、まずipairs関数を呼び出してiter関数を取得し、その都度iter関数を呼び出すことになります。

iter_function, stateless, index = ipairs(a)
iter_function(stateless, index)
1 one
iter_function(stateless, index+1)
2 two
iter_function(stateless, index+2)
3 three

もうひとつ、上のLuaのコードでは、vがnilでなければ続行すると判断していることに注意しましょう。これは、実際のforループでも同様です。例えば、下のループでは、2番目の値がnilなので、1番目の要素だけが出力されます。

a = {"one", nil, "three"}
for i, k in ipairs(a) do
 print(i, k)
end
1 one

続いて、ペアについてです。実は、上の説明でわかるように、iparsは1から始まってnilで終わるので、テーブルの中にnilがあるのに全ての要素を取り出したい場合、非常に不便なのです。そこで使えるのがpairsです。

function pairs (t)
 return next, t, nil
end

forループのロジックは前述したとおりですが、ここでのpairsの違いは、next関数の3要素とイテレートされたオブジェクトa、そして開始状態のnilを返している点です。ひとつはnext関数で、iterとは異なり次のキー値を返すこと、そしてキー値のペアがなくなって反復が終了するまで順序が固定されていることです。

いくつかの例でその違いを確認することができます。

a = {"one", "two", "three"}
for i, v in ipairs(a) do
 print(i, v)
end
for i, v in pairs(a) do
 print(i, v)
end

次のように値を表示します。

1個
/{br 2 2
3 3
1 1
2 2
3 3

このテーブルのキーは1 2 3なので、iterループを持つペア(添え字は1から始まり、nilでない最初の値まで)、nextループを持つipairs(添え字はnilから始まり、すべてのキー値をトラバースする)でも効果は同じであるため、2つの結果は同じです。

t = {
 a = "apple",
 b = "baby",
 c = "cool"
}
for i, v in ipairs(t) do
 print(i, v)
end
for k, v in pairs(t) do
 print(k, v)
end

pairsは結果をプリントアウトし、ipairsは結果を空とプリントアウトしています。t[1]の値はnilなので、ipairsループは開始と同時に停止します。

最後の例を見てみましょう(参考文献1からのコピー)。

ocal t = {
 a=100,10,20,[5]=30
}
 
for key,value in ipairs(t) do
 print(key,value) 
 -1 10
 -2 20
end
 
for key,value in pairs(t) do
 print(key,value) 
 -1 10
 -2 20
 --a 100
 --5 30
end

結果はコメントの通りですので、説明の必要はありません。

この違いを理解すれば、使い方はとても簡単です。一般にipairsは配列形式のテーブルを反復処理するために使用され、それには添え字が必要ですが、pairsは辞書形式のテーブルを反復処理するために使用することが可能です。

まとめる

上記はこの記事のすべての内容です、私はあなたの勉強や仕事のためのこの記事の内容は、特定の参照学習価値があることを願って、あなたが交換するメッセージを残すことができる質問がある場合は、BinaryDevelopのあなたのサポートをありがとうございました。

参考