我是靠谱客的博主 震动老鼠,最近开发中收集的这篇文章主要介绍groovy的Closure1.Closures的语法 2.Closures对象和调用3.Closures的参数4.委托策略5.函数编程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.Closures的语法

格式语法:{ [closureParameters -> ] statements }

{ name -> println name }

 2.Closures对象和调用

Closures是一个对象(groovy.lang.Closure),是一个匿名代码块,类似于javascript的箭头函数,例子如下

def demo = {
    it -> println it
}

 def 后紧跟着名称,这名称也是方法名,类似定义一个变量。

Closures调用方式如下

demo(xxx);
demo.call(xxx);

 xxx是需要传的参数

3.Closures的参数

Closures的参数分为3种,分别为正常参数,隐式参数和可变参数

1)正常参数

有三个特性,1.类型可选,2.参数名,3.默认值(可选)

例子如下:

def numAdd = { // 类型,默认值
    int a, int b=2 -> a+b 
} 

def numAdd2 = { // 无类型,默认值
    a,b=2 -> a+b
}

def numAdd2 = { // 无类型
     a,b -> a+b 
}
def numAdd3 = { // 有类型
     int a, int b -> a+b 
}

2)隐式参数

隐式参数:it,这个it指代是传入的参数 

代码如下:

def greeting = { it -> "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'
// it代表传入的参数

 3)可变参数

可变参数与java的可变参数一样,格式如下:type... name

例子如下

def concat1 = { String... args -> args.join('') }           
assert concat1('abc','def') == 'abcdef'                     
def concat2 = { String[] args -> args.join('') }            
assert concat2('abc', 'def') == 'abcdef'

4.委托策略

1)Closure的this指代的是什么?

在官网文档中有这样一句话

this corresponds to the enclosing class where the closure is defined

大概意思,this对应的定义closure的闭包类(最近的)而且只能是类不能是closure,这个不论是内部类还是外部类;

借用官网的例子:

class EnclosedInInnerClass {  //例子1
    class Inner {
        Closure cl = { this }                               
    }
    void run() {
        def inner = new Inner()
        assert inner.cl() == inner                          
    }
}

class NestedClosures {  // 例子2
    void run() {
        def nestedClosures = {
            def cl = { this }                               
            cl()
        }
        assert nestedClosures() == this                     
    }
}

例子1中的this指代的是Inner类,而例子2中this指代的是NestedClosures 。

2)Closure的Owner指代的是什么?

在官网文档中有这样一句话

owner corresponds to the enclosing object where the closure is defined, which may be either a class or a closure

大概意思,owner对应的创建closure的所有者,这个所有者可能是一个类或者是一个closure

借用官网的例子:

class Enclosing {// 例子1
    void run() {
        def whatIsOwnerMethod = { getOwner() }               
        assert whatIsOwnerMethod() == this                   
        def whatIsOwner = { owner }                          
        assert whatIsOwner() == this                         
    }
}
class EnclosedInInnerClass {// 例子2
    class Inner {
        Closure cl = { owner }                               
    }
    void run() {
        def inner = new Inner()
        assert inner.cl() == inner                           
    }
}
class NestedClosures {// 例子3
    void run() {
        def nestedClosures = {
            def cl = { owner }                               
            cl()
        }
        assert nestedClosures() == nestedClosures            
    }
}

例子1中的owner指代的Enclosing类,例子2中的owner指代的是Inner类,例子3中的owner指代的是名为nestedClosures的closure

3)Closure的Delegate指代的是什么?

3.1) Delegate概念

在官网文档中有这样一句话

delegate corresponds to a third party object where methods calls or properties are resolved whenever the receiver of the message is not defined

大概意思

delegate用于指定第三方对象使用。在一个Closure中使用没有定义的属性或者方法,在调用这个Closure之前,需要使用这个Closure的delegate属性指定一个对象,这个对象需要包含这个Closure之前所使用未定义的属性或者方法,这样整个调用链就完整了。

例子如下:

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

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

def upperCasedName = { delegate.name.toUpperCase() }

upperCasedName.delegate = p
assert upperCasedName() == 'NORMAN'
upperCasedName.delegate = t
assert upperCasedName() == 'TEAPOT'

说明:

第一步:定义两个类Person和Thing,初始化对象p和t,定义一个Closure(upperCasedName)使用delegate的name属性,将值大写。但是delegate属性中并没有name属性。

第二步:将upperCasedName的delegate属性指定p和t,这时调用upperCasedName  Closure,会将p和t对象初始化的值大写后返回。

更加直观的例子:

def p = new Person(name:'Igor')
def cl = { name.toUpperCase() }                 
cl.delegate = p                                 
assert cl() == 'IGOR'  

3.2)Delegate的委托策略

委托策略种类:

Closure.OWNER_FIRST默认策略,先在Closure的owner属性中检索Closure使用的方法和属性,找到直接返回,没有找到,再delegate属性中继续寻找。

Closure.DELEGATE_FIRST与Closure.OWNER_FIRST策略逻辑相反,先使用delegate属性,然后使用owner属性。

Closure.OWNER_ONLY 只在 owner属性中检索属性和方法 

Closure.DELEGATE_ONLY 只在 delegate属性中检索属性和方法

Closure.TO_SELF用户自定的策略

默认策略例子如下:

class Person {
    String name
    def pretty = { "My name is $name" }             
    String toString() {
        pretty()
    }
}
class Thing {
    String name                                     
}

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

assert p.toString() == 'My name is Sarah'           
p.pretty.delegate = t                               
assert p.toString() == 'My name is Sarah'  

说明:

没有指定策略时使用默认策略,这个例子中虽然petty的delegate指定了Thing的实例t,但是petty的owner指向person的实例,在owner中找到相应的方法或者属性直接返回了,不在delegate中检索。

指定策略例子如下:

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
cl.resolveStrategy = Closure.DELEGATE_ONLY
cl.delegate = p
assert cl() == 42
cl.delegate = t
try {
    cl()
    assert false
} catch (MissingPropertyException ex) {
    // "age" is not defined on the delegate
}

说明:

在Person定义了fetchAge的Closure后有指定到cl上,cl没有指定策略时,cl的delegate无论指向Person实例p还是Thing实例t,调用的执行结果都是42。这是因为cl的owner指向了p.fetchAge

cl的指定了委托策略只在delegate中检索,cl的delegate执行p时执行没有问题,但是当delegate指向t时出现错误,没有age属性。

5.函数编程

5.1 Currying

currying英文原意是咖喱菜,但是这里的大概意思局部变量设置。

分为三种:LeftCurrying   RightCurrying和IndexCurrying

这三种很好理解,例子如下

LeftCurrying:从Closure的参数列表的左侧设置值

def nCopies = { int n, String str -> str*n }    
def twice = nCopies.curry(2)                    
assert twice('bla') == 'blabla'                 
assert twice('bla') == nCopies(2, 'bla')

RightCurrying:从Closure的参数列表的右侧设置值

def nCopies = { int n, String str -> str*n }    
def blah = nCopies.rcurry('bla')                
assert blah(2) == 'blabla'                      
assert blah(2) == nCopies(2, 'bla')   

IndexCurrying:

def volume = { double l, double w, double h -> l*w*h }      
def fixedWidthVolume = volume.ncurry(1, 2d)                 
assert volume(3d, 2d, 4d) == fixedWidthVolume(3d, 4d)       
def fixedWidthAndHeight = volume.ncurry(1, 2d, 4d)          
assert volume(3d, 2d, 4d) == fixedWidthAndHeight(3d)   

5.2 结果缓存

Closure的执行结果会缓存起来(使用memoize()方法)(同一个方法,相同的参数,执行的结果相同,不用重新计算一次),以便快速执行;例子如下:

def fib
fib = { long n -> n<2?n:fib(n-1)+fib(n-2) }
assert fib(15) == 610 // 执行的慢

fib = { long n -> n<2?n:fib(n-1)+fib(n-2) }.memoize()
assert fib(25) == 75025 // 执行的快

5.3 Closure组合

多个Closure组合起来,一起使用

例子如下:从大到小执行

def plus2  = { it + 2 }
def times3 = { it * 3 }

def times3plus2 = plus2 << times3 //先执行times3,再执行plus2
assert times3plus2(3) == 11
assert times3plus2(4) == plus2(times3(4))

def plus2times3 = times3 << plus2
assert plus2times3(3) == 15
assert plus2times3(5) == times3(plus2(5))

// reverse composition
assert times3plus2(3) == (times3 >> plus2)(3)

5.4 递归转化(Trampoline方法)

将原来的递归(方法没有执行完成全部堆积到内存中)转换为串行调用,防止出现堆栈溢出错误

例子如下:

def factorial
factorial = { int n, def accu = 1G ->
    if (n < 2) return accu
    factorial.trampoline(n - 1, n * accu)
}
factorial = factorial.trampoline()

assert factorial(1)    == 1
assert factorial(3)    == 1 * 2 * 3

至此:Groovy的Closure全部学完,还有一些其他,如Closure嵌套等等。

最后

以上就是震动老鼠为你收集整理的groovy的Closure1.Closures的语法 2.Closures对象和调用3.Closures的参数4.委托策略5.函数编程的全部内容,希望文章能够帮你解决groovy的Closure1.Closures的语法 2.Closures对象和调用3.Closures的参数4.委托策略5.函数编程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部