たとえば、1から10までの整数のうち、指定した数だけ刻んだ数字をListに格納する処理。
具体例だと、1から10までの整数のうち、3つずつ数を刻んで格納してみます。
まずはオーソドックスにJavaっぽく。
// Javaっぽく
ArrayList<Integer> list = new ArrayList<Integer>()
for(int i =1; i <= 10; i+=3) {
list.add(i)
}
assert list == [1,4,7,10]
思いっきりJavaです。
これをもう少しGroovyっぽく変えてみる。
// Groovyっぽく
def list = []
1.step(11,3) {
list.add(it)
}
assert list == [1,4,7,10]
**.step()**メソッドはGroovyJDKの[Numberクラスにあるメソッド](http://groovy.codehaus.org/groovy-jdk/java/lang/Number.html#step(java.lang.Number, java.lang.Number, groovy.lang.Closure))です。
最初のコードよりは文字数が減ってスッキリしました。
ただ、処理の本質(stepに渡しているクロージャ)の中で必要な変数をその外で宣言しているのがイケてない。
そこで、関数型っぽく変数宣言なしで、さらにちゃんと値を返すようにしてみます。
// 関数型っぽく
assert (1..10).step(3) == [1,4,7,10]
一気にコードが短くなりました。
**(1..10)**でまずはRangeクラスのオブジェクトを取得して、.step()で、指定した値分刻んだ値のListが返されます。
で、ここで本題ですが、Number#step()とRange#step()はその終端が含まれるか含まれないか、という違いがあります(結果的に)
以下サンプルソースです。(比較がし易いように変数使ったり意図的に改行していなかったりします。)
def start = 1
def end = 10
def list1 = []; start.step(end, 3){list1.add(it)}
def list2 = (start..end).step(3)
assert list1 == [1,4,7] // endの値は含まれない
assert list2 == [1,4,7,10] // endの値が含まれる
Range#step()でも渡す値(終端)を含みたくない場合は以下の方法があります。
assert (1..10-1).step(3) == [1,4,7]
assert (1..<10).step(3) == [1,4,7]
明らかに後者の方がイケてますね!
個人的には、Number#step()よりも、関数型っぽく使えるRange#step()の方が好きです。