🐈

可変長引数の値を一つずつ操作する

2022/12/25に公開

はじめに

この記事は、Lua Advent Calendar 2022に投稿したものとなります。
前日までの記事は、リンクを参照してください。

Luaの可変長引数

Luaの関数は可変長引数を扱うことが出来ます。
使い方は、関数の仮引数リストの最後に...を設定しておくだけです。
また、関数内からもそのまま...で参照します。

local function func(...)
  print(...)
end

func("hoge", "fuga", "foo", "bar")
-- -> hoge    fuga    foo     bar

select()で一つずつ扱う

可変長引数を一つずつ操作したい場合があると思います。
そんなときはLuaの組み込み関数であるselect関数を利用します。
この関数は、第一引数にindex、第二引数に可変長引数を取り、可変長引数のindex以降の引数を全て返します。(Luaは1-indexです)

local function func(...)
  print(select(2, ...))
end
func("hoge", "fuga", "foo", "bar")
-- -> fuga    foo     bar

しかし、これでは可変長引数を一つづつ処理することは出来ません、そこでselect関数のindexに数値以外で唯一指定できる "#" という文字を利用します。

"#"を第一引数にすると、第二引数である可変長引数の値の総数を返します。

local function func(...)
  print(select("#", ...))
end
func("hoge", "fuga", "foo", "bar")
-- -> 4

また、select関数の呼び出しを()で囲むことによって、返される全ての引数における最初の引数のみを返すようにすることができます。

local function func(...)
  print((select(1, ...)))
end
func("hoge", "fuga", "foo", "bar")
-- -> hoge

これらのLuaとselect関数の仕様を利用することで可変長引数を一つづつ処理することができます。
以下がサンプルになります。

local function func(...)
  for i = 1, select("#", ...) do
    local arg = (select(i, ...))
    print(i .. ":" .. arg)
  end
end
func("hoge", "fuga", "foo", "bar")
-- -> 1:hoge
-- -> 2:fuga
-- -> 3:foo
-- -> 4:bar

まず可変長引数を取る関数内で、"#"を利用したselect関数の実行によって可変長引数の総数分のループを作成します。
そして、そのループの中で、現在のインデックス(サンプル内だと変数i)を利用するselect関数の呼び出しを括弧で囲むことによって、インデックス以降の可変長引数の内、最初の一つだけが変数argに指定されます。
このような処理を書くことでリストを一つずつ操作するような感じで可変長引数も一つずつ操作することが出来ます。

{...}を利用してリストに変換する

また、可変長引数は{...}という式によってリストに変換することも出来ます。

local function func(...)
  for i, v in ipairs({ ... }) do
    print(i .. ":" .. v)
  end
end
func("hoge", "fuga", "foo", "bar")
-- -> 1:hoge
-- -> 2:fuga
-- -> 3:foo
-- -> 4:bar

おわりに

Luaの可変長引数はselectで一つずつ操作したり、{...}でリストに変換したりすることができます。
また、Luaに限った話ではありませんが、可変長引数は関数の仮引数リストの最後に設定する必要があります。
筆者はselectについての説明を書いている途中で{...}という式を知りました。リファレンスをしっかり読むことは大事だと思います。

Discussion