前回、Ractor.selectでtakeとrecvを両方待てることがわかりました。 これを使って切符を通したときだけ通れる改札口を作ります。
完成形
キーボード入力を待つRactor = Ractor.new { loop { Ractor.yield gets.chomp } } 改札口Ractor = Ractor.new(キーボード入力を待つRactor) do |キーボード入力| ゲート = :閉 loop do # キーボード入力と自身へのメッセージを両方待つ メッセージの種類, 受信したメッセージ = Ractor.select キーボード入力, self if メッセージの種類 == :recv ゲート = :開 else Ractor.yield 受信したメッセージ if ゲート == :開 ゲート = :閉 end end end loop do 改札口Ractor.send 'に切符を入れる' 入場者 = 改札口Ractor.take p "#{入場者} が入場しました" sleep 1 end
実行すると、たくさんキー入力をしても、1秒に一回だけ受け付けます。
感想
Ractor.select
の戻り値の第一引数、自身へのイベントだと:recv
帰ってくるのですね。selfが帰ってくるのかと思っていました。
なんだろう、この・・・ES5以前のJavaScript感。懐かしい。クラスを作らないで...
- Ractorでスコープを切る
- ブロック内のローカル変数で状態を持つ
- Ractor.newで定義と同時に、外部への参照を受け取る(実行する)
モジュールパターンやんけ!
var module1 = function(initState){ var state = initState return { getState: function(){ return state }, setState: function(newVal){ state = newVal } } }('hoge')
みたいな、関数スコープしかなかった時代にプライベートな状態を持つオブジェクトを作るためにやっていた工夫と似ている点を感じました。