scala.util.control.Breaks の 実装を見てみると tryBreakable というメソッドがある。
これを使うと break でブロック式を脱出する際に break した際にだけ実行する文を記述することができる。
def tryBreakableSample { import scala.util.control.Breaks; import Breaks.{ break, tryBreakable }; tryBreakable { for (i: Int <- 1 to 5) { if (i == 3) break; print(i); } } catchBreak { print("breaked") } }
12breaked
break 後に catchBreak の後のブロックが実行されている。
注意するべきは、try 文の finally 句と違って break しなかった際には実行されないこと。
... if (i == 100) break; ...
12345
tryBreakable ... catchBreak の構造
例によって、省略記法で構造が分かりにくくなっているので省略せずに書いてみる。
def tryBreakableSample2 { import scala.util.control.Breaks; Breaks.tryBreakable( { for (i: Int <- 1 to 5) { if (i == 3) Breaks.break; print(i); } } ).catchBreak( print("breaked") ); }
ブロック式を受け取った tryBreakable が「何か」を返し、 その何かに対してブロック式を受け取る catchBreak メソッドを実行する構造になっていることがわかる。
tryBreakable ... catchBreak の実装
scala.util.control.Breaks の実装を見てみよう。
trait TryBlock { def catchBreak(onBreak: => Unit): Unit } def tryBreakable(op: => Unit) = new TryBlock { def catchBreak(onBreak: => Unit) = try { op } catch { case ex: BreakControl => if (ex ne breakException) throw ex onBreak } }
Breaks.tryBreakable が返しているのは TryBlock トレイトを実装したオブジェクト。 Breaks.tryBreakable が実行しているのはこのオブジェクトを作成して返しているだけ。
TryBlock トレイトはブロック式を受け取る catchBreak だけを持っている。
Breaks.tryBreakable が返す TryBlock トレイトオブジェクトでの catchBreak の実装は、
- TryBlock オブジェクト生成時に受け取ったブロック式(= tryBreakable の引数)を実行し、
- BreakControl がスローされたら、catchBreak の引数であるブロック式を実行する。
つまり、tryBreakable の引数として渡したブロック式が実行されるのは、 tryBreakable の中ではなく、TryBlock.catchBreak の中であることが分かった。
0 件のコメント:
コメントを投稿