Closure.DONE

Closure は便利だけれども Groovy の場合は途中で break や return *1ができない。
値を返す必要がないときは each より for を使っているが内部イテレータが必要な場合は先に findAll でフィルタリングしている。
でも Groovy も一部のメソッドは break のようなことができるみたいだ。


directive というプロパティに Closure.DONE を設定すれば、その Closure のループから抜けることができる。

assert [1,2,3] == (1..10).collect {
  if (it >= 3) directive = Closure.DONE
  it
}
  • src を検索した限り collect, collectAll, times で使える
  • findAll と比較すると最後の要素を拾ってしまうが break する分速い

検索しても使用例が Hit しないのだが、Groovy 1.0 から存在しているようだ。


directive に設定するための値としてもう一つ Closure.SKIP も定義されているがこちらは対応しているメソッドが見当たらない。
これは SKIP を設定するときには既に呼び出されているし、findAll と一致*2してしまうだろうか?


おそらく collect では使わないが Closure を引数に取るメソッドを書くときにもしかしたら役に立つかもしれないのでメモしておく。

2011-06-11 追記

10000 以下のフィボナッチ数がいくつあるか知りたい場合

// Fibonacci numbers
fibs = { n -> n <= 1 ? n : fibs(n-2) + fibs(n-1) }.memoize()

assert 21 == (0..10000).collect([] as LinkedList) {
  def f = fibs(it)
  if (f > 10000) directive = Closure.DONE
  f
}.with { it.removeLast(); it.size() }

assert 21 == [].with {
  for (i in 0..10000) {
    def f = fibs(i)
    if (f > 10000) break
    it << f  // yield
  }
  it
}.size()

[].with でリスト内包表記の変わりになることに気づいたのでやっぱり既存の API では出番がない。
DONE より SKIP があれば removeLast しなくても済んだのに。

*1:外のメソッドから

*2:2度ループしなくてよいというメリットはある