Groovy探索之delegate关键字 一

 

 

delegate关键字在Groovy语言中应用广泛,大体可以分为两个地方的使用,即在方法中使用和在闭包中使用。本系列计划用两个篇幅来谈谈delegate关键字的使用,本篇说说delegate关键字在闭包中的使用,下一个篇幅主要说说它在方法中的使用。

在Groovy语言的官方文档上,在谈到闭包的部分的时候,是这样描述this、owner和delegate这三个关键字的。

this:    跟Java一样,this指的是定义闭包的封装类。

owner:  封装对象(this或者环绕闭包)

delegate:默认情况下和owner一样,但是可以改变。

 

上面的描述虽然很清楚,但也不够详细。我们首先来举出一个例子来理解一下上面的描述:

class Testor1 { 
  
     
  
    def num = 1 
  
     
  
    def add12 = { 
  
           this.num++ 
  
    } 
  
     
  
    def add13 = { 
  
           owner.num++ 
  
    } 
  
     
  
    def add14 = { 
  
           delegate.num++ 
  
    } 
  
 
  static void main(args) { 
  
        
  
       def t = new Testor1() 
  
        
  
       t.add12() 
  
        
  
       println t.num 
  
        
  
       t.add13() 
  
        
  
       println t.num 
  
        
  
       t.add14() 
  
        
  
       println t.num 
  
     
  
  } 
  
 
}

 

运行结果为:

2

3

4

 

可以看到,上面的this、owner和delegate都指向了Testor1类的实例,果然跟官方文档描述的一样。

从上面的描述和例子可以看到,this关键字基本上很单纯,和Java语言的this用法基本一致;而owner关键字和delegate关键字的指向都是相同的,但delegate关键字的指向可以改变,因此更加的灵活。所以,基于上面的分析,我们下面的篇幅重点来谈谈delegate关键字及其相关的作用和用法,而对于this关键字和owner关键字,则不再涉及。

前面说过,Groovy语言的官方文档对于上面三个关键字的描述虽然很清楚,但是不够详细。为什么这样说呢,因为闭包的情况也比较复杂,上面简简单单的三句话并不能概括所有的情况。下面试着使用delegate关键字来举出几个例子来说明这种复杂的情况。

 

class Testor3 { 
  
     
  
    int num = 1 
  
     
  
    def add = { 
  
            
  
           delegate.num++ 
  
    } 
  
 
  static void main(args) { 
  
        
  
       def t = new Testor3() 
  
        
  
       t.add() 
  
        
  
       println t.num 
  
     
  
  } 
  
 
}

 

这个例子的运行结果为:

2

和官方文档的描述是一致的。下面我们再来看一个例子:

class Testor4 { 
  
     
  
    int num = 1 
  
     
  
    def static add = { 
  
       delegate.num++ 
  
    } 
  
 
  static void main(args) { 
  
        
  
       Testor4.add() 
  
        
  
     
  
  } 
  
 
}

 

运行的结果就报了“No such property”的错误。为什么会这样呢?其实原因很简单,就是因为闭包是静态的,它的“delegate.num++”语句中的“num”变量也只能引用静态变量,而我们的“Testor4”类中没有一个静态的“num”变量,当然会报“No such property”的错误。如果我们把上面的“Testor4”类稍稍改变,变成下面的样子:

 

class Testor4 { 
  
     
  
    static int num = 1 
  
     
  
    def static add = { 
  
       delegate.num++ 
  
    } 
  
 
  static void main(args) { 
  
        
  
       Testor4.add() 
  
        
  
       println Testor4.num 
  
     
  
  } 
  
 
}

 

则运行结果为:

2

 

明白了上面的道理,下面的一些问题就可以迎刃而解。

一个类中的闭包中的变量也可以没有三个关键字“this”、“owner”和“delegate”,请看下面的示例(例1):

 

class Testor1 { 
  
     
  
    def num = 1 
  
     
  
    def add11 = { 
  
           def num =2 
  
           num++ 
  
    } 
  
 
  static void main(args) { 
  
        
  
       def t = new Testor1() 
  
        
  
       t.add11() 
  
        
  
       println t.num 
  
         
  
  } 
  
 
}

 

运行结果为:

1

 

如果我们把上面代码的闭包中的“def num =2”去掉,变成下面的样子(例2):

class Testor1 {

def num = 1 
  
     
  
    def add11 = { 
  
           num++ 
  
    } 
  
 
  static void main(args) { 
  
        
  
       def t = new Testor1() 
  
        
  
       t.add11() 
  
        
  
       println t.num 
  
         
  
  } 
  
 
}

则结果为:

2

 

从上面的测试结果可以看出,定义在一个类中的闭包,如果它引用的变量没有任何修饰,则这个变量首先指向闭包中定义的变量,如上面的“例1”中,在闭包里定义了“def num =2”,所以接着的语句“num++”中的变量“num”指向了闭包定义的“num”,最后“println t.num”的结果就只能是1了。如果这个变量在闭包中没有定义,如“例2”,那么该变量就相当于加了“delegate”关键字修改的变量。所以语句“num++”就相当于“语句“delegate.num++”,最后“println t.num”的结果就是2了。如果在类中也没有定义该变量,那么上面的代码运行就会报“No such property”的错误了。

既然在闭包中,不加任何关键字修饰的变量在闭包找不到local变量定义时,它相当于加了“delegate”关键字的变量。那么任何“delegate”关键字给变量所带来的情况也同样发生在不加任何关键字修饰的变量上。如上面所谈到的静态闭包或者关闭定义在静态方法中给变量带来的问题。下面试着举一例:

 

class Testor5 { 
  
     
  
    static int num = 1 
  
    static def add = { 
  
       num++ 
  
    } 
  
 
  static void main(args) { 
  
        
  
       Testor5.add() 
  
        
  
       println Testor5.num 
  
     
  
  } 
  
 
}

当然了,如你所想,上面代码的运行结果为:

2

 


到此为止,我们通过一些简单的例子,明白了“ delegate ”关键字的基本用法。从来都是基本用法简单,但是在实际使用中却千变万化,从基本用法转化到实际使用需要一个艰难的过程。下面,我们就通过一个比较实际的例子,却出神入化的使用到了“ delegate ”关键字的各种用法,希望通过对这个例子的学习,我们可以从掌握“ delegate ”关键字的基础知识转化到实际使用状态。