最近また、Groovyを触り始めているのですが、いいですねこれは。数年前のClassic版しか経験がなかったのですが、速度的にも、エラーメッセージとかもずいぶん改善されています。
Groovyについて改めて何が良いと思うかというと、一つは、型付けをするプログラミングスタイルと、型付けをしないスタイルを使い分けられるところ。まあJavaと混用する以上必然なのかもしれませんが。
具体的にはまずは、変数宣言に型を指定できること。たとえば、変数に型の無いスタイル
def a = "abc";
だけではなく、
String s = "def";
とも指定できます。こうするとEclipseのGroovyプラグインでメソッド・フィールド名入力補完が効くようになります*1。良し悪しではありますけどね。
他には、例えば、'as'キーワードを使って、クロージャでインターフェースを実装することが出来ます。
たとえば、以下は1つのメソッドをもったインターフェースの場合。
interface A {
void foo(int a, int b, int c){}
}c = { a,b,c -> println "this is a closure: $a, $b, $c" } as A;
c.foo(1,2,3);
//以下が出力される
//this is a closure: 1, 2, 3
複数のメソッドを持ったインターフェースの場合は、
interface B {
void foo(int a, int b, int c);
void goo(int a, int b, int c, int d);
void goo(int a, int b, int c);
}
d = {Object[] a -> println "this is a closure: $a" } as B;
d.foo(1,2,3);
d.goo(1,2,3,4);
d.goo(1,2,3);
//以下が出力される
//this is a closure: {1, 2, 3}
//this is a closure: {1, 2, 3, 4}
//this is a closure: {1, 2, 3}
のように、1つのクロージャで全てのメソッド呼び出しをまかなうようになる*2。
マップでインターフェースを実装することも出来ます。
x = [foo: {int a, int b, int c -> println "this is a map" } ] as A;
x.foo(1,2,3);
内部的には、なんらかのラッピングクラス(マップをAにみせかけるもの)が生成されているようです。
後は余談です。
- クロージャ、マップのいずれの場合でも、インターフェースではなく、クラスに対してasすること、つまり、実装を継承することは出来ません。
- ちなみに、groovyでは、JavaScriptでそうであるように、マップはもともとオブジェクトと似た存在です。たとえば、
a = [f:{println "this is f";}]
(a.f)()
でfが呼び出せます。ただし、演算子の優先度の問題から、
(a.f)のように括弧でくくる必要があります。
もっと普通のオブジェクトのように呼びたい場合は、
a = [f:{println "this is f";}] as Expando
a.f()
のようにExpandoクラス*3にasすればOK。この場合、
def x = [ a:{println "this is a(c=$c)"; b(); },
b:{println "this is b"},
c:"hoge"] as Expando
x.a()
//以下が出力される
//this is a(c=hoge)
のように、クロージャ中から、自オブジェクトの持つ他のプロパティ(この場合c)への参照を行ったり、他のメソッドの呼び出しを行ったりすることも可能となります。
- 前述の「マップ as インターフェース」の場合、このような「Expando化」はされません(つまりクロージャから他のプロパティやメソッドの参照が出来ない)ので、不便な場合があるかもしれません。
参考リンク:
http://groovy.codehaus.org/Groovy+way+to+implement+interfaces