首页 > 代码库 > 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 闭包