resolveStrategy の基礎
G* Avent Calendar の11日目です。
たぶん、この記事を読む人は大体知ってると思いますが、先ほどロンドンから帰国したばかりです。
だいぶライフが減ってる状態なので、凝った内容は他の人に任せて、先の Groovy & Grails eXchange 2011 の Jeff Brown さんのセッション「Powerful Metaprogramming Techniques with Groovy」で説明があった Closure の resolveStrategy について軽くまとめます。
resolveStrategy とは
Closureクラスには owner と delegate という重要なプロパティがあります。owner はクロージャを宣言したオブジェクト、delegate はメソッド呼び出しの委譲先オブジェクトへの参照が保持されます。で、通常は delegate と owner と同じなので、特に気にする必要はないんですが、メソッド呼び出しの際に owner と delegate のどちらから先に見に行くか、どちらしか見ないかなどの戦略を resolveStrategy というプロパティに保持しているのです。
戦略の違いによる差異
では、動作の違いを見てみましょう。時間的にアレなので、ここではJeffさんのセッションデモのサンプルをそのままパクります。
class SomeGroovyClass { def append(String arg) { println "append was called with arg: $arg" } def doit() { def mc = { append 'Hello' append ' London' } def sb = new StringBuffer() mc.delegate = sb mc() println "SB: $sb" } public static void main(args) { def sgc = new SomeGroovyClass() sgc.doit() } }
これを実行すると・・
append was called with arg: Hello
append was called with arg: London
SB:
と出力されます。
これの戦略を変えて、delegate を先に見るようにすると
class SomeGroovyClass { def append(String arg) { println "append was called with arg: $arg" } def doit() { def mc = { append 'Hello' append ' London' } def sb = new StringBuffer() mc.delegate = sb mc.resolveStrategy = Closure.DELEGATE_FIRST mc() println "SB: $sb" } public static void main(args) { def sgc = new SomeGroovyClass() sgc.doit() } }
delegate で解決されました。
SB: Hello London
もっと詳しく知りたい方
『Groovyイン・アクション』の121-123ページがとても良いです。あとは Closureクラスのソースコードを読むのも良いかと思います。
え、『Groovyイン・アクション』もってない?
一時期法外な値段になっていましたが、今は良心的なお値段になっているので持っていない方はこの機会に入手されてはいかがでしょうか。
まとめ
ということで、かなりおおざっぱではありますが、resolveStrategy の説明をしました。
まぁ、こういう内容は id:uehaj さんとか id:fumokmm さんに深く解説してもらった方がいいと思うのですが、ロンドン帰国直後ということで大目に見てください。
次はその @fumokmm さんですね。