GroovyとJavaScriptのクロージャ
よく見るカウンタのクロージャをGroovyとJavaScriptで書いてみる。
Groovy版
def clo() { def i=0 return { i++ } } def a = clo() println "a():${a()}" // a():0 println "a():${a()}" // a():1 println "a():${a()}" // a():2 def b = clo() println "b():${b()}" // b():0 println "b():${b()}" // b():1 println "b():${b()}" // b():2 println "a():${a()}" // a():3 println "b():${b()}" // b():3
function clo() { var i=0; return function(){ return i++; }; } var a = clo(); console.log("a():" + a()); // a():0 console.log("a():" + a()); // a():1 console.log("a():" + a()); // a():2 var b = clo(); console.log("b():" + b()); // b():0 console.log("b():" + b()); // b():1 console.log("b():" + b()); // b():2 console.log("a():" + a()); // a():3 console.log("b():" + b()); // b():3
メソッド(関数)を定義しない(という表現で良いのだろうか?)場合は以下のようになる。
Groovy版
def clo = { def i = 0 return { i++ } } def a = clo() println "a():${a()}" // a():0 println "a():${a()}" // a():1 println "a():${a()}" // a():2 def b = clo() println "b():${b()}" // b():0 println "b():${b()}" // b():1 println "b():${b()}" // b():2 println "a():${a()}" // a():3 println "b():${b()}" // b():3
var clo = function(){ var i=0; return function(){ return i++; }; } var a = clo(); console.log("a():" + a()); // a():0 console.log("a():" + a()); // a():1 console.log("a():" + a()); // a():2 var b = clo(); console.log("b():" + b()); // b():0 console.log("b():" + b()); // b():1 console.log("b():" + b()); // b():2 console.log("a():" + a()); // a():3 console.log("b():" + b()); // b():3
[Groovy]追記(2012/01/11)
よくわかってないけどこうかくとエラーになる。
def clo() { x -> return { x++ } }
「->」の前に書かれたものはパラメータになるらしい。
def clo = { x -> return { x++ } } def a = clo(1) println "a():${a()}" // a():1 println "a():${a()}" // a():2 println "a():${a()}" // a():3
パラメータなしで呼び出すとエラー
def clo = { x -> return { x++ } } def a = clo() println "a():${a()}" // java.lang.NullPointerException
初期化すれば大丈夫
def clo = { x=0 -> return { x++ } } def a = clo() println "a():${a()}" // a():0 println "a():${a()}" // a():1 println "a():${a()}" // a():2 def b = clo(9) println "b():${b()}" // b():9 println "b():${b()}" // b():10 println "b():${b()}" // b():11
また、引数が一個以下なら「->」を省略可能
とあるが、
def clo = { return { x++ } } def a = clo() println "a():${a()}" // groovy.lang.MissingPropertyException
となるのはわかる。xが宣言されていないから。
ただ暗黙変数itで書いたこれが何でエラーになるのかが全然わからなかった。
def clo = { return { it++ } } def a = clo() println "a():${a()}" // java.lang.NullPointerException //def a = clo(1) //println "a():${a()}" // java.lang.NullPointerException
ちなみにこれもエラーだった。
def clo = { it=0 -> return { it++ } } def a = clo() println "a():${a()}" // java.lang.NullPointerException //def a = clo(1) //println "a():${a()}" // java.lang.NullPointerException
結果、いろいろ試したら何となくわかった。
def clo = { return { it } } def a = clo() println "a():${a()}" // null def b = clo(4) println "b():${b()}" // null
retrunで返却されるクロージャの中のitはa(とかb)の実行時の引数を見ていたらしい。
def clo = { return { it } } def a = clo() println "a(1):${a(1)}" // 1 def b = clo(4) println "b(7):${b(7)}" // 7
参考になりました。
http://groovy.codehaus.org/Japanese+Closures
groovyクロージャについて徒然と - uehaj's blog