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 类的对象 this
12     }
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 = { this }                              
22             cl()                                            // 还是 this
23         }
24         assert nestedClosures() == this
25     }
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 }                                  // 本质上还是对象的 this
12     }
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 = p
14 assert upperCasedName() == 'NORMAN'
15 upperCasedName.delegate = t
16 assert upperCasedName() == 'TEAPOT'
17 
18 // 和引用外部变量有本质区别,下面的 target 不可能被省略
19 def target = p
20 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.fetchAge
13 cl.delegate = p
14 assert cl() == 42
15 cl.delegate = t
16 assert cl() == 42                   // 默认情况下 Closure.OWNER_FIRST,所以此处断言是通过的
17 cl.resolveStrategy = Closure.DELEGATE_ONLY
18 cl.delegate = p
19 assert cl() == 42
20 cl.delegate = t
21 try {
22     cl()                            // 只取 delegate,Thing 类无 age 字段,异常
23     assert false
24 } catch (MissingPropertyException ex) {
25     // 异常会在这里被捕获
26 }

以上内容均参考 http://www.groovy-lang.org/closures.html,文档中还讲到了 closures in GStrings、currying 等很有意思的内容。

 

posted @ 2016-09-16 20:42  WendellYih  阅读(323)  评论(0编辑  收藏  举报