Pairsの話

Luaで自前でイテレーションしたい時がたまにある。
要素がnilの時の扱いがnextとpairsとかで違うからだ。
サイズを取得するときも最初にnilを発見した所までのサイズしか返さないので、適当にnilを突っ込んでるの忘れてるとよく分からないバグに遭遇したりする。


そのたびに自前で実装しよう!とか思うんだけど、なくてもまぁ困るものではないし実装がめんどくさそうなので無視してきたわけですよ。


最近ちょっとばかし余裕が出来たので実装してみた。
これであってるのかな。


それにしてもクロージャーすげぇぜ!

-- 自前pairsの実装テスト
-- "end"という文字を発見するまでkeyが1ずつ増える
function my_pairs( table_name )
	local key = 1
	-- 2つの値を返すイテレータ関数を返す.
	-- 終わらすときはnil返せばいいのかな。。。
	return function()
		if ( table_name[key] == "end" ) then
			return nil,nil
		else
			local k = key
			key = key + 1
			return k,table_name[k]
		end
	end
end


-- 適当なテーブルを渡してテスト
-- 別にこういう使い方ならpairsでも大して変わらんね
do
	local my_lst = {
		"my",
		"name",
		"is",
		nil,
		"tattyu",
		"end",
	}
	for i,v in my_pairs(my_lst) do
		if ( v ) then
			io.write(v.." ")
		else
			io.write("\n")
		end
	end
	io.write("\n")
end


結果

my name is 
tattyu


コメントにも書いてるけどこういう使い方ならpairsを使ったほうがよい。
nilで終わらせたい場合はipairsを使えばいいらしい。


たとえばitrの中で関数呼んだりするようにしたいときとかいいんじゃなかろうか。
呼び出してる側の意図しない所で関数よばれたりしてバグりそうだけどw

function my_pairs( table_name, func )
	func = func or function( v ) return v end
	local key = 1
	-- 2つの値を返すイテレータ関数を返す.
	-- 終わらすときはnil返せばいいのかな。。。
	return function()
		if ( table_name[key] == "end" ) then
			return nil,nil
		else
			local k = key
			key = key + 1
			return k,func(table_name[k])
		end
	end
end


do
	local my_lst = {
		"my",
		"name",
		"is",
		nil,
		"tattyu",
		"end",
	}

	-- 似たようなことをする関数を渡す.
	for i,v in my_pairs(my_lst,function(v)return (v and (v.." ") or "\n" )end) do
		io.write(v)
	end
	io.write("\n")
end

結果

my name is 
tattyu