Blog信息 |
blog名称: 日志总数:1304 评论数量:2242 留言数量:5 访问次数:7578138 建立时间:2006年5月29日 |

| |
[Groovy]Groovy 3 类和闭包 软件技术
lhwork 发表于 2006/12/15 15:43:14 |
灵活性是更有效地开发代码的主要因素。Groovy语言是建立在总有一天 Java 平台要包括一种敏捷开发语言这一信念上的 (Richard Monson-Haefel),因此Groovy的语法是始终围绕灵活性这个特性进行设计的。
因为 Groovy 除了是种面向过程和面向对象的语言外,它还包含了实现函数式编程一些东西。
函数编程
我们知道例如Lisp、Scheme、Haskell、ML (或其他一些语言)采用了函数式编程。但“到底什么是函数式编程 (FP)?”不幸的是,即使是函数程序员他们自己也很难对 FP 究竟是什么有个一致的认识。David Mertz 认为函数式编程粗略地描绘为至少具有以下几个特征:
函数是第一类(对象)。即,可以对“数据”进行的每样操作都可以使用函数本身做到(例如将一个函数传递给另一个函数)。将递归用作主要的控制结构。在某些语言中,不存在其它“循环”构造。重点集中在列表 LISt 处理(例如,名称 Lisp )。列表经常和子列表的递归一起使用以替代循环。“纯”函数语言能够避免副作用。这不包括在命令语言中最普遍的模式,即指定第一个,然后将另一个值指定给同一个变量来跟踪程序状态。FP 不鼓励或根本不允许出现 语句,取而代之是使用表达式求值(换句话说,即函数加上自变量)。在很纯粹的情况下,一个程序就是一个表达式(加上支持的定义)。FP 关心的是计算 什么而不是 如何计算。许多 FP 利用了“更高等级”函数(换句话说,就是函数对一些函数操作,而这些函数又对其它函数操作)。函数编程的提倡者认为所有这些特征都导致更快速的开发更短以及错误更少的代码。而且,计算机科学、逻辑和数学领域的高级理论学家发现证明函数语言和程序的正式性能比命令语言和程序容易得多。无独有偶,新发布的C# 3.0 规格书也加入了函数式编程的味道,从某些方面看起来,C# 3.0和Groovy 有点神似。
类
在字节码水平,Groovy 类是真正的 Java 类。Groovy的类与Java类相似:
方法可以基于类(static)或实例可以为public、protected或private支持常用的Java修饰符,如synchronized请注意,Groovy 1.0-JSR3与Groovy 1.0-Beta3在类定义上语法差别较大:
Groovy JSR 变量前都必须加上 def 关键字或者 private、protected 或 public 这样的修饰符;Groovy Beta3的类定义中的变量相当灵活,不需要任何关键字;(类定义外的变量不受影响。)声明属性可以用 @Property 关键字声明成员变量 ;有别于Beta3,这里P是大写的!变量默认为Private,方法默认为Public,除非使用了特定的访问修饰符;Groovy Beta3 类中定义的所有内容都默认为 public,除非定义了特定的访问修饰符;例子 1 显示了在 Groovy 语言中如何声明一个Greeter的类,它有两个public的字段name和age。注意我们是如何为它们赋值的。//无构造子的Groovy Greeterclass Greeter{ public name public age def SayHello(){ println "Hello,${name},I am Groovy" println "I am ${age} years old!" } def static Introduce(){ println "I am groovy greeter"; }}Greeter.Introduce()Greeter greeter=new Greeter(name:"Toms",age:2)greeter.SayHello()上面的例子等价于使用传统构造子的Greeter,但是更灵活。//使用传统构造子的Groovy Greeterclass Greeter{ def name def age Greeter(name,age){ this.name=name this.age=age } def SayHello(){ println "Hello,${name},I am Groovy" println "I am ${age} years old!" } def static Introduce(){ println "I am groovy greeter"; }}Greeter.Introduce()Greeter greeter=new Greeter("Toms",2)greeter.SayHello()接下来是一个复杂点的例子,其中类 Dog 有一个 getFullName 方法,它实际上返回一个表示 Dog 的全名的 String。
class Dog{ public name def bark(){ println "RUFF! RUFF!" } def getFullName(master){ name + " " + master.lname } def obeyMaster(){ println "I hear you and will not obey." }}我们可以看到,动态类型可以应用到字段和方法,因此参数类型是可选的(但是指定方法的参数类型和返回类型可以在通常的Java代码中更好的工作)。注意,最后return语句是可选(只要最后一条语句被执行,它的值就会被返回),缺省返回的是Object。例子 4 是有两个属性 fname 和 lname 和一个方法的类 DogOwner。class DogOwner{ @Property fname @Property lname def trainPet(pet){ pet.obeyMaster() }}方法调用的语法和Java类似,支持静态和实例方法。在例 5 中,我们用 Groovy对Dog和DogOwner的实例设置属性并调用了方法。//使用 Groovy 类myDog = new Dog()myDog.name = "Mollie"myDog.bark()myDog.obeyMaster()me = new DogOwner()me.fname = "Ralf"me.lname = "Waldo"me.trainPet myDog //不需要括号str = myDog.getFullName(me)println str // prints Mollie Waldo我们看到在 Dog 类的 getFullName 方法返回一个 String 对象,在这里它是 “Mollie Waldo”。
在Groovy中方法的调用可以省略括号,只要有参数,并且没有歧义。传递命名参数
在调用方法时,可以传递命名参数,参数的名字和值用分号分隔(象Map语法),参数名是唯一标识字符串。bean = new Expando(name:"James", location:"London", id:007)println "Hey " + bean.nameassert bean.id == 007注意:当前这种方法传递只实现具有Map的方法调用或JavaBean。
闭包
Groovy 中最令人兴奋和最强大的功能是支持闭包。闭包(Closure)类似于 Java
语言中的匿名内部类。闭包和匿名内部类都是可执行的一段代码,不过这两者之间有一些细微的不同。状态是自动传入传出闭包的。闭包可以有名字。它们可以重复
使用。而且,最重要且对 Groovy 同样成立的是,闭包远比匿名内部类要灵活得多!闭包用以下方法定义:{[comma-separated-Arguments-list ->] statements }闭包用“{}”括起,“->”前面是参数,后面是处理语句。下面的例子演示了如何定义并使用一个闭包。第一个闭包演示了在字符串中使用参数的形式:${param};第二个闭包演示了多参数形式:用逗号隔离参数。closure = { name -> println("hello ${name}") }closure.call("world!") closure = { greeting, name -> println(greeting + name) }closure("hello ", "world!")有趣的是,闭包至少会有一个参数 “it”,它其实是参数表中的第一个参数,所以如果闭包定义中只有一个参数,可以省略不写,而使用缺省的参数“it”。对于没有参数定义的闭包,“it”的值就是 null 。closure = { println "hello " + it }closure("world!")例子 9 展示了闭包的强大功能。新改进的 Dog 类包括一个 train 方法,它实际上执行创建了 Dog 实例的闭包。class Dog{ def train(action){ action.call() }}sit = { println "Sit, Sit! Sit! Good dog"}myDog = new Dog()myDog.train(sit) //prints Sit, Sit! Sit! Good dogmollie = new Dog()mollie.train { println "Down! DOWN!" } //prints DOWN! DOWN!在
上面的例子里,我们还看到,闭包通过 call() 方法被调用。(在底层,call()
方法实现了对闭包隐含的doCall()方法的调用)。Groovy 中的大多数对象具有像 each 和 find
这样的以闭包为参数的方法。用闭包来迭代对象会产生几种令人兴奋的可能性:[2, 4, 6, 8, 3].find { x | if (x == 3){ println x }}其实就是:(你也许已经发现,可以用it代替x)
myFinder={ x | if(x==3) println x}[2,4,6,8,3].find(myFinder)
这里我们使用了一个 Groovy-Beta3 闭包定义,只是为了让您能看懂老版本Groovy的一些例子。在新的Groovy
JSR中对闭包的定义略有改动,因为 | 字符同时也是 Java 中的位操作符;Groovy JSR 建议使用 Nice
(另外一种JRE语言)样式的 -> 分隔符代替它。这种以闭包为参数的代码在Groovy里十分普遍:
//each(1..100).each{ println it}//times 1000.times{ println it} //values go from 0 to 9999//upto1.upto(1000){ println it}//step 1.step(1001,1){ println it} //values go from 1 to 1000;更多关于闭包的内容,可以访问 500)this.width=500'>http://groovy.codehaus.org/Closures,不过有些内容可能不适用于Groovy JSR3,因为Groovy还在不断发展中。(龙二少爷) |
|
|