Posted at

GroovyのRangeを理解する

More than 3 years have passed since last update.

GroovyとRubyのRangeの違いを前に書きましたが、その関係でGroovyのRangeについても調べたのでまとめます。


基本


ドキュメント


Rangeとは

シーケンシャルな値のリストを保持できるもの。java.util.List を拡張しているので、Listっぽいアクセスの仕方ができる。

ちなみに、Range自体はインターフェースで、実装としては EmptyRange, IntRange, ObjectRangeがある。


インスタンス生成


生成方法


Groovy

def range = 1..5

assert range == [1, 2, 3, 4, 5]

..だと、終端(上記のコードだと5)を含むRange、..<だと終端を含まないRangeを作成できる。


生成されるインスタンスの型について

ちなみに、どのRangeにするかによって、生成されるインスタンスの型が異なる。


Groovy

def intRange = 1..5

assert range instanceof IntRange

def objectRange = "a".."f"
assert objectRange instanceof ObjectRange

def emptyRange = new EmptyRange()
assert emptyRange instanceof EmptyRange


EmptyRangenewしないとダメっぽい。

参考:http://stackoverflow.com/questions/15485141/empty-groovy-range


アクセス


Listっぽくアクセス

Listを継承しているので、こんな感じにアクセスできる。


Groovy

def range = 1..5

assert range.size() == 5
assert range.get(2) == 3
assert range[2] == 3
assert range.contains(5)
assert !range.contains(6)


Rangeの中身を変えるアクセスは不可(つまりimmutable)

java.lang.Listを継承しているので、add()remove()といった、Rangeの内容を変更できそうなメソッドが定義されているけど、これらを呼び出そうとすると UnsupportedOperationException を投げる。

この理由は、ObjectRangejava.util.AbstractListを、IntRangeは、java.util.AbstractList<Integer>を継承しているため。

参考:http://stackoverflow.com/questions/24889972/why-does-range-throw-unsupportedoperationexception

また、この「サポートされないオペレーションの時はUnsupportedOperationExceptionを投げる」という仕様は、Listインターフェースに記載されている。

参考:https://docs.oracle.com/javase/jp/8/docs/api/java/util/List.html


イテレーション

eachメソッドを使って走査できる。


Groovy

(1..5).each {

println "Hello ${i}"
}


swithの条件として使う

ドキュメント見て知ったけど、switchの条件判定に使える。


Groovy

switch (age) {

case 1..<6: println "未就学"
case 6..22: println "学生"
default: println "卒業"
}


拡張


独自クラスのRangeを自作する

作成するには、比較のためにjava.lang.Comparableを実装することと、next()previous()メソッドを実装する必要がある。


EnumはRangeにできる

Groovyは、JavaのEnum(Comparable実装済み)に next()previous()を付け加える。このため、EnumのRangeを作ることができる。


Groovy

enum DayOfWeek {

SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

def dayRange = DayOfWeek.SUNDAY..DayOfWeek.WEDNESDAY
assert dayRange.size() == 4
assert dayRange.contains(DayOfWeek.MONDAY)
assert !dayRange.contains(DayOfWeek.THURSDAY)


参考:http://mrhaki.blogspot.jp/2009/09/groovy-goodness-keep-your-values-in.html

Range、いろいろ便利だ。