首页 > 代码库 > groovy 闭包
groovy 闭包
语法规则
{ [closureParameters -> ] statements }
下面的语句都是正确的
1 { item++ } 2 { -> item++ } 3 { println it } 4 { it -> println it } 5 { name -> println name } 6 { String x, int y -> println "hey ${x} the value is ${y}" } 7 { reader -> 8 def line = reader.readLine() 9 line.trim()10 }
参数列表
1 def closureWithTwoArgsAndOptionalTypes = { a, int b -> a+b }2 assert closureWithTwoArgsAndOptionalTypes(1,2) == 3
可以看到参数列表使用逗号分隔,而且 typed 和 untyped 均可,-> 符号用以分隔参数列表和语句。值得提一下,如果闭包只有一个参数,那么可以省略参数列表,直接使用 it 代替参数。
委托策略
闭包有三个概念:this、owner 和 delegate
this 定义闭包的封闭类(enclosing class)
owner 定义闭包的封闭对象(enclosing object),可能是类也可能是对象
delegate 被调用方法或者引用属性的第三方对象,这个需要具体参考代码
this
1 class Enclosing { 2 void run() { 3 def whatIsThisObject = { getThisObject() } // 返回对象 this 4 assert whatIsThisObject() == this 5 def whatIsThis = { this } // 返回对象 this 6 assert whatIsThis() == this 7 } 8 } 9 class EnclosedInInnerClass {10 class Inner {11 Closure cl = { this } // Inner 类的对象 this12 }13 void run() {14 def inner = new Inner()15 assert inner.cl() == inner16 }17 }18 class NestedClosures {19 void run() {20 def nestedClosures = {21 def cl = { this } 22 cl() // 还是 this23 }24 assert nestedClosures() == this25 }26 }
可以看出 groovy 闭包中的 this 和 java 是一致的。
owner
1 class Enclosing { 2 void run() { 3 def whatIsOwnerMethod = { getOwner() } // 对象的 this 4 assert whatIsOwnerMethod() == this 5 def whatIsOwner = { owner } // 同样是对象的 this 6 assert whatIsOwner() == this 7 } 8 } 9 class EnclosedInInnerClass {10 class Inner {11 Closure cl = { owner } // 本质上还是对象的 this12 }13 void run() {14 def inner = new Inner()15 assert inner.cl() == inner 16 }17 }18 class NestedClosures {19 void run() {20 def nestedClosures = {21 def cl = { owner } 22 cl()23 }24 assert nestedClosures() == nestedClosures // 此处就是 this 就有区别了,和 owner 的语义一致25 }26 }
delegate
上面的 this 和 owner 引用的都是闭包 scope 的内容,但是 delegate 可以引用第三方对象的内容,默认 delegate 被设置为 owner,因为第三方对象不一定被设置。
1 class Person { 2 String name 3 } 4 class Thing { 5 String name 6 } 7 8 def p = new Person(name: ‘Norman‘) 9 def t = new Thing(name: ‘Teapot‘)10 11 def upperCasedName = { delegate.name.toUpperCase() } // delegate 可以省略 name.toUpperCase() 也是正确的12 13 upperCasedName.delegate = p14 assert upperCasedName() == ‘NORMAN‘15 upperCasedName.delegate = t16 assert upperCasedName() == ‘TEAPOT‘17 18 // 和引用外部变量有本质区别,下面的 target 不可能被省略19 def target = p20 def upperCasedNameUsingVar = { target.name.toUpperCase() }21 assert upperCasedNameUsingVar() == ‘NORMAN‘
修改策略
“默认 delegate 被设置为 owner”,这句话隐含意思就是 delegate 的策略可以被调整,有下面四种策略,
Closure.OWNER_FIRST 默认的
Closure.DELEGATE_FIRST delegate 优先
Closure.OWNER_ONLY 只取 owner
Closure.DELEGATE_ONLY 只取 delegate
Closure.TO_SELF 如果用户自己实现 Closure 的子类,这个才有意义
1 class Person { 2 String name 3 int age 4 def fetchAge = { age } 5 } 6 class Thing { 7 String name 8 } 9 10 def p = new Person(name:‘Jessica‘, age:42)11 def t = new Thing(name:‘Printer‘)12 def cl = p.fetchAge13 cl.delegate = p14 assert cl() == 4215 cl.delegate = t16 assert cl() == 42 // 默认情况下 Closure.OWNER_FIRST,所以此处断言是通过的17 cl.resolveStrategy = Closure.DELEGATE_ONLY18 cl.delegate = p19 assert cl() == 4220 cl.delegate = t21 try {22 cl() // 只取 delegate,Thing 类无 age 字段,异常23 assert false24 } catch (MissingPropertyException ex) {25 // 异常会在这里被捕获26 }
以上内容均参考 http://www.groovy-lang.org/closures.html,文档中还讲到了 closures in GStrings、currying 等很有意思的内容。
groovy 闭包