zoukankan      html  css  js  c++  java
  • Groovy 学习手册(6)

    9. 不可变特性

    不可变特性和函数式编程在一起就像是花生酱和果酱在一起一样。虽然没有必要非要在一起使用,但他们相处得很好。

    在纯正的函数式语言中,每个函数对本身之外没有影响,即没有副作用。这意味着每次调用函数时,返回相同输入的相同值。

    为了适应这种行为,需要不可变的数据结构。不可变的数据结构不能直接更改,但每次操作都返回一个新的数据结构。
    例如,Scala语言里的 Map 就是不可变的。

    val map =  Map("Smaug" -> "deadly")
    val  map2 =  map + ("Norbert" -> "cute")
    println(map2) // Map(Smaug -> deadly, Norbert -> cute)
    

    所以,在上面的代码中,map是保持不变的。
    每个语言里都会提供一个关键字来定义一个变量或值是不可变的,在 Java 中使用 final 关键字来表示,Groovy 里面也是一样。

    public class Centaur {
        final String name
        public  Centaur(name) {this.name=name}
    }
    Centaur c = new  Centaur("Bane");
    println(c.name) // Bane
    c.name = "Firenze" //error
    

    除此而外,Groovy 还提供了 @Immutable 注解来标注一个类为不可变类。它也提供了默认的构造方法,还有带有属性的构造方法,hashCode 方法,equals 方法和 toString 方法。下下面的例子。

    import groovy.transform.Immutable
    @Immutable
    public class Dragon  {
        String name
        int scales
    }
    Dragon smaug = new  Dragon('Smaug', 499)
    println smaug
    // Output: Dragon(Smaug, 499)
    

    10. Groovy Fluent GDK

    在 Groovy 中,findAll和其他方法可以用在任何对象上,但尤其用在 List,Set,Range 上更加好用。除了findAllcollectinject还有以下的方法都可以在 Groovy 中使用。

    • each:根据给定的闭包条件遍历所有的值;
    • eachWithIndex:在遍历值时带有两个参数,一是具体的值,二是值对应的索引;
    • find:根据匹配的闭包条件找到满足条件的第一个元素;
    • findIndexOf:根据匹配的闭包条件找到满足条件的第一个元素,并返回对应的索引。

    例如,collect方法用在对 List 的元素操作上非常简单。

    def  list = ['foo','bar']
    def newList = []
    list.collect( newList ) { it.substring(1) }
    println newList //  [oo, ar]
    

    在另一个例子里,

    def dragons = [new Dragon('Smaug', 499), new Dragon('Norbert', 488)]
    String longestName = dragons.
        findAll { it.name != null }.
        collect { it.name }.
        inject("") { n1, n2 -> n1.length() > n2.length() ? n1 : n2 }
    

    上面的代码首先查找所有不为 null 的名字,收集对象元素里的的名字属性,然后再使用聚合方法找到所有名字里最长的那个。

    11. Groovy Curry

    curry方法用来在给闭包里的参数预定义一个默认值。它可以接受多个参数,并且在你预想的情况下从左到右逐一替换。请看下面的代码:

    def  concat = { x, y -> return  x + y }
    // closure
    def  burn = concat.curry("burn")
    def inate = concat.curry("inate")
    

    因为你只提供了第一个参数,它们的闭包会准备已经给定的字符串,burn方法准备了“burn”字符串,而inate方法准备了“inate”字符串。
    burn(" wood") // == burn wood
    你还可以使用composition闭包应用于两个方法和一个输入参数。

    def composition = { f, g, x -> return f(g(x)) }
    def burninate = composition.curry(burn, inate)
    def  trogdor = burninate(' all the people')
    println "Trogdor: ${trogdor}"
    // Trogdor: burninate all the people
    

    函数组合是函数编程中的一个重要思想。它允许你组合多个功能在一起创建复杂的算法。

    12. 方法句柄

    方法句柄允许你引用实际方法,就像它们是闭包一样。当你想使用现有的方法,而不是闭包,或者你只是想一个替代的闭包语法时,这是非常有用的。例如,给定一个方法:

     def breathFire(name) { println "Burninating $name!" }
    

    在定义了breathFire方法的类里面可以做如下操作:

     ['the country side', 'all the people'].each(this.&breathFire)
    

    这样就会把breathFire方法作为一个闭包传递给 each 方法,然后会打印如下结果:

    Burninating the country side
    Burninating all the people
    

    13. 尾递归

    在 Groovy 1.8版本中,trampoline方法被用来引入到闭包中用于对尾递归的优化。这允许闭包被顺序调用而不是内存堆积,从而避免栈溢出和提高性能。
    从Groovy 2.3 版本以后,可以使用trampoline方法来解决递归,甚至更好的办法是使用注解 @TailRecursive, 例如,

    import groovy.transform.*
    @TailRecursive
    long  totalPopulation(list, total = 0) {
      if (list.size() == 0)
        total
      else
        totalPopulation(list.tail(), total + list.first().population)
    }
    

    在 Groovy 的 List中,tail 方法会返回不包含第一个元素的 List,而first方法则返回 List 的第一个元素。直接上代码:

    @Canonical class City {int population}
    def cities = (10..1000).collect{new City(it)}
    totalPopulation(cities)
    // 500455
    
  • 相关阅读:
    base64这种编码的意义
    玩2k16
    http://riddle.arthurluk.net walkthrough
    sshfs
    其它技术名称解释
    解决Apache日志"internal dummy connection"方法
    Aliyun OSS Nginx proxy module(阿里云OSS Nginx 签名代理模块)
    php-imagick扩展
    phpinfo空白
    Docker数据管理-数据卷 data volumes和数据卷容器data volumes containers的使用详解
  • 原文地址:https://www.cnblogs.com/IcanFixIt/p/6670508.html
Copyright © 2011-2022 走看看