@m_seki の

I like ruby tooから引っ越し

selectっぽい字面

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

まだありそう

いずれにしても、操作もさせつつ待つ(遅れた方は却下する)のでインターフェイスが固定的になっちゃうのかなあ。