Groovy探索之delegate关键字 一(2)
from: http://blog.csdn.net/hivon/archive/2008/10/27/3156043.aspx
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*"关键字的基础知识转化到实际使用状态。
这个例子首先要从一个GroovyBean说起:
class Person
{
String name
}
这是一个很简单的GroovyBean类,下面,我们为这个GroovyBean类做了一个Builder类,如下:
class PersonBuilder {
def persons = []
def persons(Closure closure)
{
closure.delegate = this
closure()
return this.persons
}
def getProperty(String propertyName)
{
this.persons<<new Person(name:"${propertyName}")
}
}
先不要看这个builder类,我们先来看看如何使用这个builder类,我们在“PersonBuilder”类里加入如下的一个“main”方法:
static void main(args) {
def pers = new PersonBuilder().persons{
mike
alice
tom
mark
}
pers.each{
println it.name
}
}
这个“main”方法的运行结果为:
mike
alice
tom
mark
正是这个很简单的功能,却完完整整的为我们演示了“delegate”关键字的功能。我们首先来看“main”方法。
我们为“PersonBuilder”类的“persons”方法传入了如下的一个闭包:
{
mike
alice
tom
mark
}
下面,我们来看“PersonBuilder”类的“persons”方法:
def persons(Closure closure)
{
closure.delegate = this
closure()
return this.persons
}
我们先不管第一个语句行:“closure.delegate = this”,来看第二个语句行:
closure()
即执行传入的闭包。那么闭包里有些什么语句呢?很简单,就是执行四个变量:
mike
alice
tom
mark
值得注意的是,这个四个变量没有任何关键字来修饰,前面我们说过,如果闭包里的变量没有任何关键字来修饰,那么首先看闭包里有没有把该变量定义成local变量,我们可以再看看传入的闭包,没有在闭包的任何地方把它们四个变量定义成local变量。所以这个四个语句行就相当于下面的四个语句行:
delegete.mike
delegete.alice
delegete.tom
delegete.mark
学过Gpath的人都知道,在Groovy语言中,“delegete.mike”相当于如下的调用如下的语句:
delegate.getMike()
另外的三个语句如此类推。这就意味着我们希望在“PersonBuilder”类中有“getMike”这类的方法。我们再看看“PersonBuilder”类,虽然没有显式的“getMike”这类的方法,但是有一个“getProperty”方法。我们知道,在Groovy语言中,“getProperty”方法会分派所有的“get”方法,不管是“getMike”还是“getAlice”,都会调用“getProperty”方法。
所以,通过以上的分析,我们闭包的四个语句都会调用“getProperty”方法。而“getProperty”方法干了些什么事呢?
this.persons<<new Person(name:"${propertyName}")
看看上面的语句,很简单,就是以闭包里的变量名作为参数,来实例化一个Person类对象,然后把这个对象add到一个名为“persons”的List对象里存起来。
到目前为止,我们已经分析了“PersonBuilder”类的工作原理,但却漏掉了一个最重要的要点,没有它,这个“PersonBuilder”类的构思再好,也是实现不了的。那么这个要点是什么呢?
我们在谈“PersonBuilder”类的“persons”方法的时候,放下了第一个语句行:
closure.delegate = this
那么,这个语句行有什么用呢?
我们还是可以先做一个测试,将这个语句行从“PersonBuilder”类中注销掉,那么,“PersonBuilder”类就变成了下面的样子:
class PersonBuilder {
def persons = []
def persons(Closure closure)
{
//closure.delegate = this
closure()
return this.persons
}
def getProperty(String propertyName)
{
this.persons<<new Person(name:"${propertyName}")
}
static void main(args) {
def pers = new PersonBuilder().persons{
mike
alice
tom
mark
}
pers.each{
println it.name
}
}
}
现在,我们运行上面的“main”方法,结果如下:
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: mike for class: PersonBuilder
at groovy.lang.MetaClassImpl.invokeStaticMissingProperty(MetaClassImpl.java:730)
这个Exception很长,我只截取了前面两句话。为什么会抛出“No such property”的错误呢?
我们再来看看“main”方法,发现闭包:
{
mike
alice
tom
mark
}
是定义在“main”方法里的,而“main”方法是一个静态方法,而我们前面说过,像“mike”这样的语句相当于“delegete.mike”。基于这个一个原因,“delegete.mike”中的“delegate”肯定指向“PersonBuilder”类,而“delegete.mike”语句肯定会调用“PersonBuilder”类的静态的“getMike”方法。
而上面的“PersonBuilder”类中没有静态的“getMike”这类的方法,当然就会报“No such property”的错误了。
基于这样的分析,如果我们在上面的“PersonBuilder”类加入如下的静态方法:
def static getMike()
{
this.persons<<new Person(name:"mike")
}
那么,是不是在执行闭包里的“mike”语句行时,就不会报错了呢?
我们把“getMike()”方法加入到“PersonBuilder”类中,然后,再将“persons”变量也变成静态变量。如下所示:
class PersonBuilder {
def static persons = []
def persons(Closure closure)
{
//closure.delegate = this
closure()
return persons
}
def getProperty(String propertyName)
{
persons<<new Person(name:"${propertyName}")
}
def static getMike()
{
persons<<new Person(name:"mike")
}
static void main(args) {
def pers = new PersonBuilder().persons{
mike
alice
tom
mark
}
pers.each{
println it.name
}
}
}
执行,结果为:
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: alice for class: delegateBuilder.PersonBuilder
at groovy.lang.MetaClassImpl.invokeStaticMissingProperty(MetaClassImpl.java:730)
可以看到,“No such property”的错误是报在“alice”变量的上面。这说明,“mike”可以正常的执行了。
现在,我们就基本上可以猜测“closure.delegate = this”语句行的作用了。由于闭包“closure”是定义在静态方法中,我们当然希望它定义在非静态方法中,而闭包的“delegate”变量又刚好是可以改变的。
所以,我们通过“closure.delegate = this”语句行来改变闭包的“delegate”变量的指向,将它指向“this”,而刚好“this”又是指向当前对象的。这就使得闭包定义在一个非静态方法里。就使得闭包中的语句行可以使用“getProperty”方法了。而我们的“PersonBuilder”类达到了我们要想的目的。
可以说,这个例子是一个很好的使用了闭包关键字“delegate”的例子。虽然我们不会在实际中使用这个例子,但它给我们的启示依然是很重要的。我们很好的理解了这个例子,才可以在实际的编程中灵活的使用闭包的“delegate”关键字。
From: Alex wang
Sent: Friday, November 14, 2008 9:09 PM
To: grailsunion@googlegroups.com
Subject: [grailsunion:73] [转]Groovy探索之delegate关键字
原文是 这里: http://www.java2000.net/p11260 ,不过我打开这个连接firefox会死,是通过google快照查看的。
========================================================================================
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类的实例,果然跟官方文档描述的一样。
...
分享到:
相关推荐
Termux (Android 5.0+).apk.cab
【资源说明】 基于go、vue开发的堡垒机系统(运维安全审计系统)全部资料+详细文档.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
制作报表
本项目为金山培训大作业源码汇总,采用C++与Qt技术构建,包含401个文件,涵盖106个C++源文件、72个头文件、41个PNG图片、27个项目文件以及HTML、JavaScript、CSS等多种文件类型。项目包含四个主要模块:KVector向量库、命令行会议系统、KSvg绘图板和KHttp音乐播放器。尽管最终未能入选,但展现了作者在C++编程和Qt框架应用方面的扎实功底和努力。
内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
【资源说明】 基于课程设计:C语言爬虫、详细文档+全部资料+高分项目.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
《自动控制原理》是自动化及相关专业的重要课程,涵盖了控制系统的基础理论和分析方法。这份资料集是针对杭州电子科技大学自动控制原理课程的期末复习资源,包含了试卷答案和复习PPT,对于学习者来说是一份非常宝贵的参考资料。 我们来看文件"9自控原理第五章习题参考答案.doc",它提供了第五章的习题解答。第五章通常涉及根轨迹法,这是分析线性系统稳定性的一种图形方法。通过绘制根轨迹,我们可以直观地理解系统动态性能的变化,例如系统的稳定性、超调量和调节时间等。 接着,"1第一章作业(答案).docx"涵盖了课程的初步概念,如控制系统的基本组成部分、控制系统的定义以及开环与闭环控制的区别。第一章的内容通常包括控制系统的基本模型,如传递函数和信号流图。 "10测试4.docx"和"13第7章测试.docx"可能是关于控制系统设计和分析的测试题目,可能涉及到频率响应分析或状态空间模型等内容。第七章常常讨论系统稳定性分析,比如奈奎斯特稳定判据或劳斯判据。 "7测试1.docx"可能包含有关拉普拉斯变换和控制系统动态特性的问题,这是控制系统分析的基础工具。 "4自动控制第二章习题答案.pdf"提供了第二章习题
066 - 直播逗大哥话术
AOP项目demo 案例
皮带输送线3D+2DCAD+加工件标准件清单BOMsw2016可编辑全套技术资料100%好用.zip
154-基于stm32单片机花样流水灯设计Proteus仿真+源程序.zip
鲸鱼WOA-XGboost拟合预测建模模型,数据格式多维自变量输入,单维因变量输出,直接替数据就可以使用,程序内注释详细
项目均经过测试,可正常运行! 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea
RocketDock-v1.3.5是一款专为Windows 7设计的桌面工具,它模仿Mac OS X的Dock功能,通过直观的图标排列提高应用启动效率。该工具提供快捷启动、动画效果、自定义设置以及扩展性,使用户能够根据个人喜好调整Dock栏并减少桌面杂乱。安装和设置过程简单,配有详细的说明文件,帮助用户更好地了解和使用工具。
会员制医疗预约服务管理信息系统的作用,可以提高会员制医疗预约服务管理的工作人员的效率,协助他们对会员制医疗预约服务信息进行统一管理,为管理者提供信息储存和查询搜索系统。一个良好的会员制医疗预约服务管理信息系统可以实现对会员制医疗预约服务的精细化管理:对在线会员制医疗预约服务管理流程的全过程进行电子化操作,其主要作用是管理和控制会员制医疗预约服务所有的信息,分析库存数据,使工作人员对会员制医疗预约服务管理信息系统进行监管,根据系统所提供的相应信息,采取适当的措施,及时补救管理中的漏洞,提高在线会员制医疗预约服务管理的工作效率,使得在线会员制医疗预约服务管理变的更加系统和规范。 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea
**CCNA(思科认证网络助理工程师)是网络技术领域中的一个基础认证,它涵盖了网络基础知识、IP编址、路由与交换技术等多个方面。以下是对CCNA中文版PPT中可能涉及的知识点的详细说明:** ### 第1章 高级IP编址 #### 1.1 IPv4地址结构 - IPv4地址由32位二进制组成,通常分为四段,每段8位,用点分十进制表示。 - 子网掩码用于定义网络部分和主机部分,如255.255.255.0。 - IP地址的分类:A类、B类、C类、D类(多播)和E类(保留)。 #### 1.2 子网划分 - 子网划分用于优化IP地址的分配,通过借用主机位创建更多的子网。 - 子网计算涉及掩码位数选择,以及如何确定可用的主机数和子网数。 - CIDR(无类别域间路由)表示法用于更有效地管理IP地址空间。 #### 1.3 私有IP地址 - 为了节省公网IP地址,私有IP地址被用于内部网络,如10.0.0.0/8,172.16.0.0/12,192.168.0.0/16。 #### 1.4 广播地址 - 每个网络都有一个特定的广播地址,所有数据包都会发送到这个地址以达到同一网络内的所有设备。
项目实现了对特产信息管理、特产分类管理、特产分类管理、特产评分管理、系统管理、订单管理等业务进行管理。 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea
随着21世纪网络和计算机技术的飞速发展,它们已经与我们的日常生活紧密融合。当前网络的运行速度已经达到千兆级别,覆盖范围广泛,深入到生活的每一个角落。这一进步推动了管理系统的发展,使得远程处理事务、远程工作信息管理和实时追踪工作状态成为可能。网上管理系统以其前所未有的体验满足了新时代的工作需求,因此得到了大力发展。 本系统是一个个人日常事务管理系统,利用计算机和网络技术开发的在线平台,能够实现日常安排、消费记录和重要提醒设置等功能。系统采用SSM框架和Vue技术,数据库使用MySQL,开发环境为Eclipse。系统用户角色包括普通用户和管理员,功能涵盖个人中心管理、用户管理、日常安排管理、消费记录管理和重要提醒管理。用户可以记录消费、安排日常事务和设置重要提醒,而管理员则负责管理用户信息和基础数据信息。该系统不仅方便了用户和管理员,还提高了个人事务管理的效率,更适应现代人的生活方式。
项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea、微信开发者工具 数据库:MySql5.7以上 部署环境:maven 数据库工具:navicat
如何使用Python和PIL库生成带竖排文字的封面图像