微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Groovy 1.8 新特性: 增强的DSL和闭包特性

虽然 JDK7 千呼万唤不出来,Groovy 还是如期升级到 1.8 版本。大致读了下 Release Notes,改动不大(大了还得了),但是亮点还是有的。

加强的 DSL 特性:

把 Scala 和旧版的 Groovy 进行比较,会发现 Groovy 被迫写了很多点和括号,而 Scala 则看起来更像是自然的英语。前几天我还絮叨过这个问题,但现在有所不同了

   1: turn left then right
   2: paint wall with red,green and yellow

印象深刻!

在新版本中,a b c d 等同于 a(b).c(d),由此,可以写出更自然的 DSL。(支持多参数、闭包和命名参数)

PS: 对多数人来说,写 DSL 的情况不多,但是多半接触过 Gradle、Grails 等工具,多少会有了解。要做出好的设计,必须对 command chains 的模式(谁知道有没有现有的模式对应?我记得以前用过一种不断返回自身的连续接口,中文叫啥来着,和这个类似,但要简单很多)很熟悉。即使不写 DSL,在脚本中应用以上的特性也是很能改善可读性的。

性能提升:

1.8.x 将对基础类型和方法调用做大量的优化(目前 int 的四则运算和比较已经被优化了)。Groovy 由于其动态模型必须在计算前作大量的检查,在新版本中,如果符合一定的前提条件,则这些检查将被略过,从而加快执行速度。

PS II. 如果细读文档会发现这些优化目前仅针对相当受限的条件,比如提到的整数运算,如果你计算 int + int,那么就可以得到优化的速度,可如果计算 int + int + long 则立刻回到原有的模式。但需要强调的是,代码原来怎么写,现在还怎么写,不要去迎合这些优化。否则,1.9 版本一出,难道重写所有代码

PS III. 而且我对 Groovy 的性能要求也不高,至少以前单位里的那些小白鼠也没有因为我用了 Groovy 就来投诉我的。就算万一遇到瓶颈了,还可以用 Groovy++ 来顶一下。以前没有吧 Groovy++ 作为首选,但现在 Groovy 的 Windows 安装包里已经认包含了 Groovy++,官方的态度也算是不言自明了吧。

GPars

说实在,这个我真不太关心。主要是觉得要是这玩意管用,那我的 Scala 不是白学了么,老子又不是搞科研的

Smile

。话虽如此,多核时代,多点选择还是好的。

增强的闭包!!

这个喜欢。

首先是闭包现在可以作为注释的参数了:(例程我改过了,原来的代码能说明意思,但本身有问题)

1: import java.lang.annotation.*
   2:  
   3: @Retention(RetentionPolicy.RUNTIME)
   4: @interface Invariant {
   5:     Class value() //此处value()将返回注释参数的class
   6: }
   7:  
   8: @Invariant({ number >= 0 }) //在新版本中,闭包可以作为注释的参数
   9: class distance {
  10:     def number,unit
  11: }
  12:  
  13: //以下我对Release Notes中的范例做了修改,原版的代码显然是……错的
  14: def anno = distance.getAnnotation(Invariant) //这里和Java的用法相同
  15:  
  16: Object[] args = [[number: 12],[unit: 'km']] //这是针对下一行的newInstance函数(Groovy的Class类方法
  17: def check = anno.value().newInstance(args) //注意这里check是distance下的闭包,而不是distance的实例
  18: println check.class
  19:  
  20: assert check()

这二十行代码可能看起来没有什么用,但对于框架设计者来说则提供了很多有趣的可能。(比如“按合约设计”)

然后是闭包之间的组合(这个帅呆了)

1: triple = { it * 3 }
   2: square = { it ** 2 }
   3:  
   4: tripleBeforeSquare = triple >> square
   5: assert tripleBeforeSquare(1) == 9 // square(triple(1))
   6:  
   7: tripleAfterSquare = triple << square
   8: assert tripleAfterSquare(1) == 3 // triple(square(1))

Trampoline!

1: /*
   2: factorial = {
   3:     it > 1 ? factorial(it - 1) * it : 1
   4: }
   5: 
   6: factorial 1000
   7: */
   8:  
   9: rec = { n,f = 1G -> // 1G的写法表示BigInteger
  10:     n > 1 ? rec.trampoline(n - 1,n * f) : f
  13: factorial = rec.trampoline()
  14:  
  15: factorial 1000 toString() size() // 2560位的大数,你不会想把它打印出来的

在注释掉的部分,我们看到了一个旧式的阶乘闭包。这个闭包不太管用,因为过深的递归将造成溢出错误。通过新的 Trampoline 闭包,Groovy “不太优雅”的解决了这个问题。

PS IV: 之所以说不太优雅,是和 Scala 的尾递归相比较而言的。但毫无疑问,到目前为止,这个新特性可能是以后最为常用的特性之一。

闭包缓存

新版本中,闭包的结果可以进行缓存(假设给定相同的参数必定返回相同的结果)

1: cls = { ... do something ... }.memoize()
   2: // .memoizeAtMost(max) 最多缓存max个结果
   3: // .memoizeAtLeast(min) 至少缓存min个结果
   4: // .memoizeBetween(min,max) 缓存min到max个结果

出人意料的新功能!以前总是用 map 来实现简单的缓存,现在直接用闭包就可以做到。当然,危险性则是这个闭包是否总是针对相同的参数返回相同的结果。(毕竟 Groovy 不是纯粹的函数风格)

Currying

一个伪装的函数风格!(注意,这一特性也被加入了 1.7 的最新版本)

1: divide = { a,b -> a / b }
   3: // 反向的 currying:被替换的是b(右侧)而不是a
   4: halve = divide.rcurry(2)
   5: assert halve(4) == 2
   7: // curry化索引为n的参数
   8: halve2 = divide.ncurry(1,2)
   9: assert halve2(4) == 2

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐