元组和集合

在 Scala 创建一个元组类型非常的简单,这只是主体的一部分:如果首先将元素公开给外部,那么在类型内部创建描述这些元素的名称就毫无价值。考虑清单 3:

清单 3. tuples.scala

 // JUnit test suite  
    //  
    class TupleTest  
    {  
      import org.junit._, Assert._  
      import java.util.Date  
       
      @Test def simpleTuples() =  
      {  
        val tedsStartingDateWithScala = Date.parse("3/7/2006")  
     
        val tuple = ("Ted", "Scala", tedsStartingDateWithScala)  
          
        assertEquals(tuple._1, "Ted")  
        assertEquals(tuple._2, "Scala")  
        assertEquals(tuple._3, tedsStartingDateWithScala)  
      }  
    } 

 

创建元组非常简单,将值放入一组圆括号内,就好象调用一个方法调用一样。提取这些值只需要调用 “_n” 方法,其中 n 表示相关的元组元素的位置参数:_1 表示第一位,_2 表示第二位,依此类推。传统的 Java java.util.Map 实质上是一个分两部分的元组集合。

元组可以轻松地实现使用单个实体移动多个值,这意味着元组可以提供在 Java 编程中非常重量级的操作:多个返回值。例如,某个方法可以计算 String 中字符的数量,并返回该 String 中出现次数最多的字符,但是如果程序员希望同时 返回最常出现的字符和 它出现的次数,那么程序设计就有点复杂了:或是创建一个包含字符及其出现次数的显式类,或将值作为字段保存到对象中并在需要时返回字段值。无论使用哪种方 法,与使用 Scala 相比,都需要编写大量代码;通过简单地返回包含字符及其出现次数的元组,Scala 不仅可以轻松地使用 “_1”、“_2” 等访问元组的各个值,还可以轻松地返回多个返回值。

如下节所示,Scala 频繁地将 Option 和元组保存到集合(例如 Array[T] 或列表)中,从而通过一个比较简单的结构提供了极大的灵活性和威力。

创建元组非常简单,将值放入一组圆括号内,就好象调用一个方法调用一样。提取这些值只需要调用 “_n” 方法,其中 n 表示相关的元组元素的位置参数:_1 表示第一位,_2 表示第二位,依此类推。传统的 Java java.util.Map 实质上是一个分两部分的元组集合。

元组可以轻松地实现使用单个实体移动多个值,这意味着元组可以提供在 Java 编程中非常重量级的操作:多个返回值。例如,某个方法可以计算 String 中字符的数量,并返回该 String 中出现次数最多的字符,但是如果程序员希望同时 返回最常出现的字符和 它出现的次数,那么程序设计就有点复杂了:或是创建一个包含字符及其出现次数的显式类,或将值作为字段保存到对象中并在需要时返回字段值。无论使用哪种方 法,与使用 Scala 相比,都需要编写大量代码;通过简单地返回包含字符及其出现次数的元组,Scala 不仅可以轻松地使用 “_1”、“_2” 等访问元组的各个值,还可以轻松地返回多个返回值。

如下节所示,Scala 频繁地将 Option 和元组保存到集合(例如 Array[T] 或列表)中,从而通过一个比较简单的结构提供了极大的灵活性和威力。

数组带

      object ArrayExample1  
    {  
      def main(args : Array[String]) : Unit =  
      {  
        for (i <- 0 to args.length-1)  
        {  
          System.out.println(args(i))  
        }  
      }  
    } 

 

您走出阴霾

让我们重新审视一个老朋友 — 数组 — 在 Scala 中是 Array[T]。和 Java 代码中的数组一样,Scala 的 Array[T] 是一组有序的元素序列,使用表示数组位置的数值进行索引,并且该值不可以超过数组的总大小,如清单 4 所示:

 

尽管等同于 Java 代码中的数组(毕竟后者是最终的编译结果),Scala 中的数组使用了截然不同的定义。对于新手,Scala 中的数组实际上就是泛型类,没有增加 “内置” 状态(至少,不会比 Scala 库附带的其他类多)。例如,在 Scala 中,数组一般定义为 Array[T] 的实例,这个类定义了一些额外的有趣方法,包括常见的 “length” 方法,它将返回数组的长度。因此,在 Scala 中,可以按照传统意义使用 Array,例如使用 Int 在 0 到 args.length - 1 间进行迭代,并获取数组的第 i 个元素(使用圆括号而不是方括号来指定返回哪个元素,这是另一种名称比较有趣的方法)。 

扩展数组

事实证明 Array 拥有大量方法,这些方法继承自一个非常庞大的 parent 层次结构:Array 扩展 Array0,后者扩展 ArrayLike[A],ArrayLike[A] 扩展 Mutable[A],Mutable[A] 又扩展 RandomAccessSeq[A],RandomAccessSeq[A] 扩展了 Seq[A],等等。实际上,这种层次结构意味着 Array 可以执行很多操作,因此与 Java 编程相比,在 Scala 中可以更轻松地使用数组。

例如,如清单 4 所示,使用 foreach 方法遍历数组更加简单并且更贴近函数的方式,这些都继承自 Iterable 特性:

  object   
    {  
      def main(args : Array[String]) : Unit =  
      {  
        args.foreach( (arg) => System.out.println(arg) )  
      }  
    } 

 

看上去您没有节省多少工作,但是,将一个函数(匿名或其他)传入到另一个类中以便获得在特定语义下(在本例中指遍历数组)执行的能力,是函数编程的 常见主题。以这种方式使用更高阶函数并不局限于迭代;事实上,还得经常对数组内容执行一些过滤 操作去掉无用的内容,然后再处理结果。例如,在 Scala 中,可以轻松地使用 filter 方法进行过滤,然后获取结果列表并使用 map 和另一个函数(类型为 (T) => U,其中 T 和 U 都是泛型类型),或 foreach 来处理每个元素。我在清单 6 中采取了后一种方法(注意 filter 使用了一个 (T) : Boolean 方法,意味着使用数组持有的任意类型的参数,并返回一个 Boolean)。

清单 6. 查找所有 Scala 程序员

 

 class ArrayTest  
    {  
      import org.junit._, Assert._  
        
      @Test def testFilter =  
      {  
        val programmers = Array(  
            new Person("Ted", "Neward", 37, 50000,  
              Array("C++", "Java", "Scala", "Groovy", "C#", "F#", "Ruby")),  
            new Person("Amanda", "Laucher", 27, 45000,  
              Array("C#", "F#", "Java", "Scala")),  
            new Person("Luke", "Hoban", 32, 45000,  
              Array("C#", "Visual Basic", "F#")),  
      new Person("Scott", "Davis", 40, 50000,  
        Array("Java", "Groovy"))  
          )  
     
        // 查找所有Scala程序员 ...  
        val scalaProgs =  
          programmers.filter((p) => p.skills.contains("Scala") )  
          
        // 应该只有2  
        assertEquals(2, scalaProgs.length)  
          
        // ... now perform an operation on each programmer in the resulting  
        // array of Scala programmers (give them a raise, of course!)  
        //  
        scalaProgs.foreach((p) => p.salary += 5000)  
          
        // Should each be increased by 5000 ...  
        assertEquals(programmers(0).salary, 50000 + 5000)  
        assertEquals(programmers(1).salary, 45000 + 5000)  
          
        // ... except for our programmers who don't know Scala  
        assertEquals(programmers(2).salary, 45000)  
     assertEquals(programmers(3).salary, 50000)  
      }  
    }  

 

创建一个新的 Array 时将用到 map 函数,保持原始的数组内容不变,实际上大多数函数性程序员都喜欢这种方式:

清单 7. Filter 和 map

 @Test def testFilterAndMap =  
    {  
      val programmers = Array(  
          new Person("Ted", "Neward", 37, 50000,  
            Array("C++", "Java", "Scala", "C#", "F#", "Ruby")),  
          new Person("Amanda", "Laucher", 27, 45000,  
            Array("C#", "F#", "Java", "Scala")),  
          new Person("Luke", "Hoban", 32, 45000,  
            Array("C#", "Visual Basic", "F#"))  
    new Person("Scott", "Davis", 40, 50000,  
      Array("Java", "Groovy"))  
        )  
     
      // Find all the Scala programmers ...  
      val scalaProgs =  
        programmers.filter((p) => p.skills.contains("Scala") )  
        
      // Should only be 2  
      assertEquals(2, scalaProgs.length)  
        
      // ... now perform an operation on each programmer in the resulting  
      // array of Scala programmers (give them a raise, of course!)  
      //  
      def raiseTheScalaProgrammer(p : Person) =  
      {  
        new Person(p.firstName, p.lastName, p.age,  
          p.salary + 5000, p.skills)  
      }  
      val raisedScalaProgs =   
        scalaProgs.map(raiseTheScalaProgrammer)  
        
      assertEquals(2, raisedScalaProgs.length)  
      assertEquals(50000 + 5000, raisedScalaProgs(0).salary)  
      assertEquals(45000 + 5000, raisedScalaProgs(1).salary)  
    }  

 

注意,在清单 7 中,Person 的 salary 成员可以标记为 “val”,表示不可修改,而不是像上文一样为了修改不同程序员的薪资而标记为 “var”。

Scala 的 Array 提供了很多方法,在这里无法一一列出并演示。总的来说,在使用数组时,应该充分地利用 Array 提供的方法,而不是使用传统的 for ... 模式遍历数组并查找或执行需要的操作。最简单的实现方法通常是编写一个函数(如果有必要的话可以使用嵌套,如清单 7 中的 testFilterAndMap 示例所示),这个函数可以执行所需的操作,然后根据期望的结果将该函数传递给 Array 中的 map、filter、foreach 或其他方法之一。

 

posted @ 2014-12-05 13:59  R星月  阅读(281)  评论(0编辑  收藏  举报
作者:lishaoying 出处:http://www.cnblogs.com/rxingyue 说明:本文是自己学习编程的一个历程,版权归作者和博客园共有,欢迎转载,请标明原文连接,如有问题联系我 Email:983068303@qq.com,非常感谢。

作者:lishaoying
出处:http://www.cnblogs.com/rxingyue
说明:本文是自己学习编程的一个历程,版权归作者和博客园共有,欢迎转载,请标明原文连接,如有问题联系我,非常感谢。