gradle学习笔记(三) Groovy闭包

版权声明:本文为博主原创文章,转载请注明出处 https://github.com/baiiu https://blog.csdn.net/u014099894/article/details/51118703

前言:

接着 gradle 学习笔记(二) ,来学习Groovy中闭包。

官方文档 Closures
Groovy API

1. 闭包基础:

1. 概念:
A closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable.
Groovy中的闭包是一段 开放的、匿名的代码。

2. 闭包格式:

     {
          [closureParameters -> ] 
          statements 
      }

闭包[closureParameters->] 是可选的,看起来像一个List,并且这些参数的类型可以不写。

3. 举个例子:

{ String x, int y -> //参数                                
    println "hey ${x} the value is ${y}" //statement语句
}

2. 闭包用法

第一步,创建闭包变量:

创建闭包有三种方法:

 //使用 def 声明一个闭包
 def listener = { e -> println "Clicked on $e.source" }

 //使用指定类型 Closure 声明一个闭包
 Closure callback = { println 'Done!' }     

 //使用泛型 声明一个固定返回类型的闭包
 Closure<Boolean> isTextFile = {
    File it -> it.name.endsWith('.txt') //返回boolean类型
} 

第二步,调用闭包:

闭包是一个匿名的代码块,不能像调用方法那么调用。下面说明怎么调用闭包。

示例1,无参闭包

def code = {123}; //省去了参数和箭头
println code(); //调用该闭包
println code.call(); //另外一种调用方式

示例2,带参数闭包


//是否为奇数
def isOddNumber = {
  int i -> //声明参数
  i%2 == 1;//可以省略return语句
};

println isOddNumber(3);
println isOddNumber.call(3);

3. 闭包参数说明:

第一种,普通的参数

  • 可以不写参数类型
  • 可以给参数一个默认值
def closureWithOneArg = { str -> str.toUpperCase() }; //不写参数类型
println closureWithOneArg('groovy') == 'GROOVY' //传入错误类型会报错

//另一个例子
def closureWithTwoArgs = { a,b -> a+b } 
println closureWithTwoArgs(1,2); //传入不能相加的类型会报错

//默认参数值
def closureWithTwoArgAndDefaultValue = { int a, int b=2 -> a+b }
println closureWithTwoArgAndDefaultValue(1); //调用时候都可以少写一个,很方便

第二种,隐式参数 Implicit parameter

如果闭包没定义参数的话,则隐含有一个参数,这个参数名字叫 it
it 代表闭包的参数。

def greeting = { "Hello, $it!" }; //隐含参数it

//相当于
def greetingT = {
    it ->
    // return "Hello , $it"; //GString 用法
    return "Hello, " + it + "!";
}
println greeting("Patrick");


//所以上面那个判断奇数的闭包就可以这样写
def isOddNumber = { it % 2 == 1};
println isOddNumber(3);

因为在不指定参数时,有一个默认参数 it,那么该怎么指定无参的闭包呢。是这样:

def magicNumber = { -> 42 }; //使用箭头表示前面无参!!
magicNumber();

第三种,可变参数

//可变参数
def aMethod = {
  int... args ->  //  ...表示可变
  int sum = 0;
  args.eachWithIndex{ //遍历求和
  it,i ->
  sum = sum + args[i];
  }
  return sum;
};
println aMethod(1,2,3);


4. 闭包的Delegation代理

The ability to change the delegate or change the delegation strategy of closures make it possible to design beautiful domain specific languages (DSLs) in Groovy.
Groovy中的闭包具有能够改变代理或代理策略的这种能力,使得我们能够使用它设计出很优美的DSL语言。

要想理解Groovy中的delegation,必须要理解以下几个概念

1. 理解this,owner

Groovy中的闭包内置了3个不同的对象, 可以直接使用:

  • this 指闭包所在的最近的类 .class
  • owner 指定义闭包的宿主,不仅仅是类,还可能是一个闭包
  • delegate 代理
class NestedClosures {
    void run() {
        def nestedClosures = {//嵌套闭包
            def cl = { owner } //owner指的就是该闭包的宿主, 即nestedClosures,即第一层闭包                             
            cl()
        }
        assert nestedClosures() == nestedClosures            
    }
}


class NestedClosures {
    void run() {
        def nestedClosures = {//嵌套闭包
            def cl = { this }//指的是最近的class,即NestedClosures.class的示例对象                     
            cl()
        }
        assert nestedClosures() == this                     
    }
}

2. 理解delegate

While this and owner refer to the lexical scope of a closure, the delegate is a user defined object that a closure will use.
this和scope是Groovy内置在closure中的对象,那么delegate就是用户指定的一个对象,用于closure使用。delegate默认使用的是owner。

基础介绍:

class Enclosing {
    void run() {
        def cl = { getDelegate() }//使用getDelegete()方法获取closure的delegate
        def cl2 = { delegate } //  使用 delegate获取
        assert cl() == cl2()    
        assert cl() == this  //默认使用owner,最近的类
        def enclosed = {
            { -> delegate }.call()                        
        }

        //默认使用owner,最近的闭包对象  
        assert enclosed() == enclosed;           
    }
}

delegate可以被设置为不同的对象

class Person {
    String name
}
class Thing {
    String name
}

def p = new Person(name: 'Norman')
def t = new Thing(name: 'Teapot')

//定义一个闭包,使用delegate获取名字,并返回大写值
def upperCasedName = { delegate.name.toUpperCase() }

upperCasedName.delegate = p //设置为p,则返回NORMAN
assert upperCasedName() == 'NORMAN'
upperCasedName.delegate = t //设置为t,则返回TEAPOT
assert upperCasedName() == 'TEAPOT'


/*
the delegate can be used transparently, that is to say without prefixing method calls with delegate.
delegate对象可以被透明的使用,即不需要在方法前面显示声明delegate.
*/
class Person {
    String name
}
def p = new Person(name:'Igor')

//并没有delegate.name,默认是owner,owner没有name属性,所以使用delegate的name属性
def cl = { name.toUpperCase() }              
cl.delegate = p //设置delegate                                 
assert cl() == 'IGOR'   

2. delegate strategy 代理的代理策略

上面提到的最后一个示例,就是使用了代理策略。delegate的策略默认是Closure.OWNER_FIRST ,所有在宿主没有name属性时,就会使用delegate的属性,如果delegate也没有,那就报错啦。

delegate有如下几个策略:

  • Closure.OWNER_FIRST is the default strategy. If a property/method exists on the owner, then it will be called on the owner. If not, then the delegate is used.

  • Closure.DELEGATE_FIRST reverses the logic: the delegate is used first, then the owner

  • Closure.OWNER_ONLY will only resolve the property/method lookup on the owner: the delegate will be ignored.

  • Closure.DELEGATE_ONLY will only resolve the property/method lookup on the delegate: the owner will be ignored.

  • Closure.TO_SELF can be used by developers who need advanced meta-programming techniques and wish to implement a custom resolution strategy: the resolution will not be made on the owner or the delegate but only on the closure class itself. It makes only sense to use this if you implement your own subclass of Closure.

示例:

class Person {
    String name
    int age
    def fetchAge = { age }
}
class Thing {
    String name
}

def p = new Person(name:'Jessica', age:42)
def t = new Thing(name:'Printer')
def cl = p.fetchAge
cl.delegate = p //设置代理
assert cl() == 42 
cl.delegate = t
assert cl() == 42 //owner优先,fetchAge是一个闭包,它的owner是Person

cl.resolveStrategy = Closure.DELEGATE_ONLY //修改策略
cl.delegate = p
assert cl() == 42
cl.delegate = t
try {
    cl()
    assert false //呵呵,delegate上面没有该属性,报错
} catch (MissingPropertyException ex) {
    // "age" is not defined on the delegate //没有定义
}

结语

这一篇文章主要学习了闭包的基本用法和基本概念,几乎全是看着官方文档过来的,有点像翻译了。目前对闭包的了解还是比较基础,之后不断在不断的使用过程中再加深理解。闭包这块很多语言都有该特性,像C、swift、js等等,在学习Groovy时候打好基础,对之后的学习肯定有帮助。

恩,文章几乎差不多翻译了官方文档,若是有误的地方,多多勘正啊。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页