2011-08-25 5 views
19

私は最初の引数としてファイルハンドルを取るデバッグプリント関数を作成しようとしています。まず、私はこのような関数を書く:Luaでは、nilを含むvarargsを扱う正しい方法は何ですか?

function fprint (f, ...) 
    for i, v in ipairs{...} do 
     f:write(tostring(v)) 
     f:write("\t") 
    end 
    f:write("\n") 
end 

この機能は、限り、私は、引数にnil値を渡さないように動作します。しかし、私がnilでこれを呼び出すと、nilの値と残りの引数が表示されません。

fprint(io.stderr, 1, 2, nil, 3) 
=> prints only 1 and 2 

この問題を解決する正しい方法は何ですか?

答えて

26

実際には、nilの値をvarargsで扱うのは簡単です。nil(実際のパラメータ数をカウントします)でも機能するselect関数を使用するだけです。次の慣用法は、それがLuaの5.2のコアライブラリ関数table.packになるように便利です。

function table.pack(...) 
    return { n = select("#", ...), ... } 
end 

それらを反復処理するために、これだけ使うように、引数の数は、フィールドnに格納されます。

function vararg(...) 
    local args = table.pack(...) 
    for i=1,args.n do 
     -- do something with args[i], careful, it might be nil! 
    end 
end 
+1

甘い!私は '選択'について知りませんでした。 – torus

+2

最も有用な追加点は、テーブルを単に '解凍'できないことです。解凍するには: 'local tbl = {n = select("# "、...)、...}; print(unpack(tbl、1、tbl.n)); ' – Aidiakapi

+0

この回答は公式ウィキで詳しく議論されました:http://lua-users.org/wiki/VarargTheSecondClassCitizen –

2

#操作は、nilの後ろの任意の位置を指すことができるため、nilエントリを含む配列の長さを知ることは容易ではありません。 nilが印刷されます。あなたはスキップすることができた場合は

function last_index(array) 
    local max = 0 
    for k, _ in pairs(array) do 
    max = math.max(max, k) 
    end 
    return max 
end 

function fprint (f, ...) 
    local parm={...} 
    for i=1,last_index(parm) do 
     f:write(tostring(parm[i])) 
     f:write("\t") 
    end 
    f:write("\n") 
end 

function fprint (f, ...) 
    local parm={...} 
    for i=1,#parm do 
     f:write(tostring(parm[i])) 
     f:write("\t") 
    end 
    f:write("\n") 
end 

むしろ#に中継よりも、あなたはparmテーブルが配列である知っていると、このようなものを使用するので、あなたは、複雑な(したがって、実装に依存しない)を取得することができますnil値と順序は重要ではない場合は、pairsに切り替えるほうがはるかに簡単です。

+0

ありがとうございました!私はペアに切り替えようとします。 – torus

+0

明らかに、マイケルの答えは最高です、私は自分自身も+1しましたが、ダウン投票の理由は他にありますか? – BMitch

+0

私は2つの答えの両方upvoted :) – torus

関連する問題