今回は Closure クラスに定義されている、制御構造に関するメソッドもしくは制御構造風に使えるメソッドを見ていきます。 今回扱うメソッドと定数は以下の通り:
boolean isCase(Object candidate) int getDirective() void setDirective(int directive) static int DONE static int SKIP
isCase() メソッド
isCase() メソッドは Groovy で特別に使われるメソッドで
- switch 文
- in 文
- コレクションの grep() メソッド
などの制御を行えます。 ここでは switch 文での使用例を見ていきましょう。
Closure の isCase() メソッドは、クロージャを実行した返り値のオブジェクトに対して asBoolean() メソッド呼んだ結果が返されます*1。 これを利用して、switch 文の case 部分にクロージャを書くことができます。 boolean 値を返すクロージャを使って
def i = 3 switch(i){ case { it % 2 == 1 }: // it (ここでは変数 i になる)を2で割ったあまりが1なら、この分岐。 assert true break default: assert false }
となります。 また、返り値が boolean 値でない場合は asBoolean() が呼ばれます。 ここでは文字列を返すクロージャを使用した場合のサンプルを見ておきましょう(空文字列は false と評価される):
def s = '' switch(s){ case { it }: // s が空文字列なので、この分岐は使われない。 assert false break default : assert true }
null が返された場合は(asBoolean() メソッドはないけど) false と判定されるので、例外が投げられる心配はありません。
directive
次は、直接制御構造と関係しているわけではないのですが、クロージャの directive を見ていきます。 クロージャの directive とは、コレクションの要素にクロージャを適用する際に、while や for 文の中で break, continue 文が行うような繰り返しの制御を可能にするものです。 ただし、クロージャの directive で制御できるのは collect() メソッドのみのようで、each() メソッドや find() メソッドなどでは使えません。 使い方はこんな感じ:
def result = (1..<10).collect{ i -> if(i % 3 == 0) directive = Closure.DONE i } assert result == [1, 2, 3]
クロージャの directive プロパティに Closure.DONE (定数)をセットすると、それ以降の要素に対してクロージャが適用されないようになります。 同じことを for 文で書くと、以下のようになります:
def result = [] for(i in 1..<10){ result << i if(i % 3 == 0)break } assert result == [1, 2, 3]
for 文の中の要素の追加( result << i)と if 文の順序が逆になっていることに注意。 もしこの順序をもとのままに書くと
def result = [] for(i in 1..<10){ if(i % 3 == 0)break result << i } assert result == [1, 2]
となって、結果が異なります(要素 3 がない)。 そもそもクロージャで directive を使うのは Groovy っぽくないコードなようなので使わない方が無難。 大抵の場合 findAll() メソッドなどでフィルターをかければ事足りるかと。
ちなみに、上記の例では Closure.DONE を使いましたが、Closure.SKIP は同じような使い方はできません。 そもそも Closure.SKIP を読み取って制御を行うメソッドはないようで、自分で directive プロパティにセットしたり読み取ったりして使うようです。 詳しくはこちらを参考:
- コードの恵み「Closure.DONE」
- flow control in closures
- 作者: 関谷和愛,上原潤二,須江信洋,中野靖治
- 出版社/メーカー: 技術評論社
- 発売日: 2011/07/06
- メディア: 単行本(ソフトカバー)
- 購入: 6人 クリック: 392回
- この商品を含むブログ (152件) を見る
*1:null, 0, 空文字列、空リスト、空マップなどは false と判定されます。