Groovy の getAt

Groovy では演算子の多重定義によって a[b] は a.getAt(b) の呼び出しに置き換えられる。
a, b のクラスは自由なので、次のようなこともできる。

class Greeting {
  def text
}

class Say {
  def getAt(Greeting greeting) {
    println greeting.text
  }
}

new Say()[new Greeting(text: "hello")]


標準で getAt を実装しているクラスには、配列、String、Map、List、Object、Matcher、Date などがある。
それぞれに対応した b が存在する。


Range を指定できる場合は Collection も指定できるように多重定義されているので次のようなことができる。

[1,2,3,4,5][0..1,2,3..4]     // [1,2,3,4,5]
[1,2,3,4,5][0..1,[2,[3..4]]] // 再帰的に呼び出されるのでこのような指定もできる


getAt は a の対応するメソッド呼び出すだけなので、範囲外を指定すると様々な例外が発生する。*1
範囲外を指定しても例外にならないのは List.getAt(int) で i >= size の場合だけである。
IntRange の指定は int の指定の集合ではない。

[1,2,3][10]     // null が返る
[1,2,3][0..2,3] // [1,2,3,null] が返る
[1,2,3][0..3]   // IndexOutOfBoundsException
[1,2,3][-1..0]    // [3,2,1] が返る
[1,2,3][-1..0,-4] // ArrayIndexOutOfBoundsException
"abc"[10]       // StringIndexOutOfBoundsException
([1,2,3] as int[])[10]  // getAt ではなく Java 呼び出しなので ArrayIndexOutOfBoundsException

*1:対応するメソッドが例外を発生させるのだから、normaliseIndex の例外はいらなかったのではないか? empty にも対応できるし