Gradle Cheat Sheet (2): Groovy Closures and Objects

  Groovy可以通过Closure(闭包)来定义函数,闭包有两个特点:闭包可以像数值和字符串类型那样被赋给变量,也可以访问其作用域外的变量。

1. 闭包的声明和调用

  使用def 声明闭包,注意这里和声明函数相比多了等号= :

def foo = "One million dollars"
def myClosure = {
    println "Hello from a closure"
    println "The value of foo is $foo"
}

  闭包的调用和函数类似:

myClosure()

输出为:

Hello from a closure
The value of foo is One million dollars

注意foo的定义在myClosure的作用域之外,myClosure可以获取其作用域之外的变量。

  一个闭包实际上是groovy.lang.Closure的实例,可以把闭包赋给变量:

def bar = myClosure
def baz = bar
baz()

输出为:

Hello from a closure
The value of foo is One million dollars

2. 闭包的参数

  使用-> 分隔参数列表和闭包体,形式上类似于Lambda表达式。

def doubleIt = { x -> x + x}

3. 高阶函数

  Groovy支持高阶函数(Higher order function),可以把函数作为参数传递给函数。如:

def applyTwice(func, arg){
    func(func(arg))
}
foo = 5
def fooDoubledTwice = applyTwice(doubleIt, foo)
println "Applying doubleIt twice to $foo equals $fooDoubledTwice"

输出为:

Applying doubleIt twice to 5 equals 20

applyTwice 的第一个参数func 是一个函数,在arg 上应用两次func 。

  这里函数作为“一等公民”,像数值和字符串类型一样进行传递,可以实现函数式编程的范式。如:

def myList = ["Gradle", "Groovy", "Android"]
def printItem = {item -> println "List item: $item"}
myList.each(printItem)

输出为:

List item: Gradle
List item: Groovy
List item: Android

即在列表myList 的每一个元素上执行闭包printItem 。

  可以在行内定义闭包,如果闭包只接受一个参数,则可以直接用it指代:

myList.each{println "Compactly printing each list item: $it"}

输出为:

Compactly printing each list item: Gradle
Compactly printing each list item: Groovy
Compactly printing each list item: Android

4. 委托

  闭包可以拥有委托对象,如果闭包中用到的变量和方法在闭包本地没有定义,则会继续在闭包的委托对象中寻找。

  首先定义一个GroovyGreeter类:

class GroovyGreeter {
    String greeting = "Default greeting"
    def printGreeting(){println "Greeting: $greeting"}
}

def myGroovyGreeter = new GroovyGreeter()

myGroovyGreeter.printGreeting()
myGroovyGreeter.greeting = "My custom greeting"
myGroovyGreeter.printGreeting()

输出为:

Greeting: Default greeting
Greeting: My custom greeting

这里对GroovyGreeter 类的定义使用了简化的方法,但其本质还是一个Java类。Groovy会自动为类的成员变量(如greeting)添加getter和setter。

  然后定义greetingClosure 如下:

def greetingClosure = {
    greeting = "Setting the greeting from a closure"
    printGreeting()
}

注意greetingClosure 中没有定义printGreeting() ,直接运行greetingClosure() 会报错。这里希望greetingClosure 中的printGreeting() 使用GroovyGreeter 中的同名函数,就需要先通过greetingClosure.delegate 把之前实例化的myGroovyGreeter 设置为greetingClosure 的委托对象:

greetingClosure.delegate = myGroovyGreeter
greetingClosure()

输出为:

Greeting: Setting the greeting from a closure

 

本部分的完整代码可以在这里找到。