goのselectっぽいやつ、実装できそうな気もするけど字面がなあ。
a. 引数に操作オブジェクトを渡す
成功したチャネルの操作オブジェクトと値を返すやつ。
同じチャネルに複数の操作したときにwhenでマッチさせにくい。selectの実引数の操作オブジェクトを別途メモする必要があるため。
(チャネルは操作オブジェクトと===でtrueになるようにしてはある)
Fiber.new do while true c, value = Bartender::select(quit.pop!, chan[0].pop!, chan[1].pop!, chan[2].pop!, chan[3].pop!, chan[4].pop!, ch2.push!(:x)) case c when chan[0] p [0, value] when chan[1] p [1, value] when chan[2] p [2, value] when chan[3] p [3, value] when chan[4] p [4, value] when ch2 p [:ch2, value] when quit p [:quit, value] break else p :else end Bartender.sleep(rand) end end.resume
b. selectコンテキスト
selectコンテキストオブジェクトに操作とチャネル、成功した時のブロックを渡す。
文字数多くてキモい。
Fiber.new do catch(:quit) do while true Bartender::select2 do |select| select.read(quit) do |value| p [:quit, value] throw(:quit) end.read(chan[0]) do |value| p [0, value] end.read(chan[1]) do |value| p [1, value] end.read(chan[2]) do |value| p [2, value] end.read(chan[3]) do |value| p [3, value] end.read(chan[4]) do |value| p [0, value] end.write(ch2, :x) do p :ch2 end.else do p :else end end Bartender.sleep(rand) end end end.resume
まだありそう
いずれにしても、操作もさせつつ待つ(遅れた方は却下する)のでインターフェイスが固定的になっちゃうのかなあ。