美文网首页JAVAScala首页投稿(暂停使用,暂停投稿)
《七周七语言:理解多种编程范型 第5章 Scala》笔记

《七周七语言:理解多种编程范型 第5章 Scala》笔记

作者: 每天学点编程 | 来源:发表于2016-07-18 22:46 被阅读316次

    5.1 关于Scala

    5.1.1 与Java的密切关系

    • Scala运行在Java虚拟机上,这使得Scala可以和现存的应用同时运行。
    • Scala可以直接使用Java类库,使得开发人员可以利用现有的框架和遗留代码。
    • Scala和Java一样都是静态类型语言,因此这两种语言遵循一样的编程哲学。
    • Scala的语法与Java比较接近,使得开发人员可以快速掌握语言基础。
    • Scala既支持面向对象泛型也支持函数式编程泛型,这样开发人员就可以逐步在代码中运用函数式编程的思想。

    5.1.2与Java的不同之处

    类型推断

    Scala类型推断的极限在哪里?什么情况下必须要指定变量的类型?

    函数式编程概念

    可以通过不同方式使用已有的函数构造出新函数。

    不变量

    变量是否可变必须一开始就明确,如果不知道变量是否可变,那么就应该指定为不可变的。
    在这种理念的指导下,Scala会要求你明确地决定一个变量是否可变。

    高级程序构造

    5.1.4函数式语言特性

    • 函数式程序由函数组成。
    • 函数总是具有返回值。
    • 函数对于相同的输入总是会返回相同的值。
    • 函数式程序禁止改变状态或修改数据。一旦你设置了一个值,就无需再管它了。

    Scala并不是一门纯函数式编程语言。

    5.2 第一天

    5.2.1 Scala 类型

    Scala Hello World

    整数是对象。

    scala> "abc" + 4
    res6: String = abc4
    
    scala> 4 + "abc"
    res7: String = 4abc
    
    scala> 4 + "1.0"
    res8: String = 41.0
    

    即使上面的代码没有报错,也不能按照java的思路去理解,"abc" + 4应该理解为字符串有+(i:int)这个方法,而4 + "abc"应该理解为int有一个+(str : String)方法。

    本来以为在java中会报错的,结果没有:

    public class App 
    {
        public static void main( String[] args )
        {
            System.out.println(4 + "abc");
            System.out.println("abc" + 4);
            System.out.println(4 + "1.0");
        }
    }
    
    scala> 4 * "abc"
    <console>:12: error: overloaded method value * with alternatives:
      (x: Double)Double <and>
      (x: Float)Float <and>
      (x: Long)Long <and>
      (x: Int)Int <and>
      (x: Char)Int <and>
      (x: Short)Int <and>
      (x: Byte)Int
     cannot be applied to (String)
           4 * "abc"
             ^
    

    Scala是强类型的,使用类型推断,并可以在编译期间进行类型检查(不需要声明变量的类型,并不代表变量是没有类型的)。

    scala> var i = 1
    i: Int = 1
    
    scala> i = "abc"
    <console>:12: error: type mismatch;
     found   : String("abc")
     required: Int
           i = "abc"
               ^
    

    Scala在编译期间绑定变量类型。
    i就是int类型,并且不可以改变。

    5.2.2 表达式与条件

    scala> 5 < 6
    res10: Boolean = true
    
    scala> 5 <= 6
    res11: Boolean = true
    
    scala> 5 <= 2
    res12: Boolean = false
    
    scala> 5 >= 2
    res13: Boolean = true
    
    scala> 5 != 2
    res14: Boolean = true
    

    if表达式

    scala> val a = 1
    a: Int = 1
    
    scala> val b = 2
    b: Int = 2
    
    scala> if ( b < a) {
         |     println("true")
         | } else {
         |     println("false")
         | }
    false
    

    var声明不变量,var声明变量

    空值、0不可转换为布尔值

    强类型是指这门语言检查两种类型是否兼容,如果不兼容则会抛出一个错误或强制类型转换。
    静态类型语言强迫在类型结构的基础上执行多态。

    scala> Nil
    res16: scala.collection.immutable.Nil.type = List()
    
    scala> if (0) { println("true")}
    <console>:12: error: type mismatch;
     found   : Int(0)
     required: Boolean
           if (0) { println("true")}
               ^
    
    scala> if (Nil) {println("true")}
    <console>:12: error: type mismatch;
     found   : scala.collection.immutable.Nil.type
     required: Boolean
           if (Nil) {println("true")}
               ^
    

    java中空值、0不可转换为布尔值


    Paste_Image.png

    5.2.3 循环

    object App {
      def whileLooop {
        var i = 1
        while (i <= 3) {
          println(i)
          i += 1
        }
      }
      def main(args: Array[String]) = {
        whileLooop
      }
    }
    

    在Scala中,public是默认的可见级别。

      def forLoop {
        var args = Array(1, 2, 4)
        println("for loop using Java-style iteration")
        for (i <- 0 until args.length) {
          println(args(i))
        }
      }
      def main(args: Array[String]) = {
        forLoop
      }
    
    
    
    object App {
    
      def rubyStyleForLoop(args: Array[String]) {
        println("for loop using Ruby-style iteration")
        args.foreach { arg =>  
          println(arg)  
        }
      }
      def main(args: Array[String]) = {
        rubyStyleForLoop(Array("a", "b", "c"))
      }
    }
    

    5.2.4范围与元组

    范围

    scala> val range = 0 until 10
    range: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    scala> range.start
    res0: Int = 0
    
    scala> range.end
    res1: Int = 10
    
    scala> range.step
    res2: Int = 1
    
    scala> (0 to 10) by 5
    res3: scala.collection.immutable.Range = Range(0, 5, 10)
    
    scala> (0 to 10) by 6
    res4: scala.collection.immutable.Range = Range(0, 6)
    
    scala> (0 to 10 by 6)
    res5: scala.collection.immutable.Range = Range(0, 6)
    
    scala> (0 until 10 by 5)
    res6: scala.collection.immutable.Range = Range(0, 5)
    
    scala> val range = (10 until 0) by -1
    range: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
    
    scala> val range = (10 until 0 by -1)
    range: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
    
    scala> val range = 10 until 0 by -1
    range: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
    
    //方向是无法被推断出来的
    scala> val range = (10 until 0)
    range: scala.collection.immutable.Range = Range()
    
    scala> val range = (0 to 10)
    range: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3, 4, 5, 6, 7
    , 8, 9, 10)
    
    scala> val range = 'a' to 'e'
    range: scala.collection.immutable.NumericRange.Inclusive[Char] = NumericRange(a,
     b, c, d, e)
    
    

    begin to end包括end
    begin until end不包括end

    scala> 0 to 10
    res0: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3, 4, 5, 6, 7,
     8, 9, 10)
    
    scala> 0 until 10
    res1: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    

    元组

    元组是一个固定长度的对象集合。元组中的对象可以具有不同类型。 在纯函数式编程语言中,程序员经常用元组便是对象以及它们的属性。

    scala> val person = ("Elvis", "Presley")
    person: (String, String) = (Elvis,Presley)
    
    scala> person._1
    res2: String = Elvis
    
    scala> person._2
    res3: String = Presley
    
    scala> person._3
    <console>:13: error: value _3 is not a member of (String, String)
           person._3
    

    Scala使用元组而不是列表进行多值赋值

    scala> val (x, y) = (1, 2)
    x: Int = 1
    y: Int = 2
    
    scala> val x,y = 1,2
    <console>:1: error: ';' expected but ',' found.
    val x,y = 1,2
               ^
    

    元组具有固定长度。

    scala> val (a, b) = (1, 2, 4)
    <console>:11: error: constructor cannot be instantiated to expected type;
     found   : (T1, T2)
     required: (Int, Int, Int)
           val (a, b) = (1, 2, 4)
    

    5.2.5 Scala中的类

    scala> class Person(firstName: String, lastName: String)
    defined class Person
    
    scala> new Person
    <console>:13: error: not enough arguments for constructor Person: (firstName: St
    ring, lastName: String)Person.
    Unspecified value parameters firstName, lastName.
           new Person
           ^
    
    scala> new Person("xiaoming", "huang")
    res9: Person = Person@7412a438
    
    
    
    
    class Compass {
      //{}内的全部内容都是构造函数的
      val directions = List("north", "east", "south", "west")
      var bearing = 0
      print("Initial bearing: ")
      println(directions)
      
      
      def direction() = directions(bearing)
      
      def inform(turnDirection: String) {
        println("Turning " + turnDirection + ". Now bearing " + direction)
      }
      
      def turnRight() {
        bearing = (bearing + 1) % directions.size
        inform("right")
      }
      
      def turnLeft() {
        bearing = (bearing + (directions.size - 1)) % directions.size
        inform("left")
        
      }
    }
    object App {
    
      
      def main(args: Array[String]) {
         val myCompass = new Compass
        
            myCompass.turnRight()
          myCompass.turnRight()
          
          myCompass.turnLeft()
          myCompass.turnLeft()
          myCompass.turnLeft()
          myCompass.turnLeft()
      }
      
    }
    

    辅助构造器

    
    
    class Person(first_name: String) {
      println("Outer constructor")
      
      def this(first_name: String, last_name: String) {
        this(first_name)
        println("Inner constructor")
      }
      
      def talk() = println("Hi")
      
    }
    object Person{
      def main(args: Array[String]) {
        val bob = new Person("Bob")
        val bobTate = new Person("Bob", "Tate")
      }
    }
    
    

    5.2.6 扩展类

    1.伙伴对象和类方法

    object TureRing {
      def rule = println("To rule them all")
    }
    

    上面代码创建了一个单件(singleton)对象。在Scala中,对象定义和类定义可以具有相同的名称。可以在一个单件对象的声明中创建类方法而在类声明中创建实例方法。

    2.继承

    
    class Person(val name: String) {
      def talk(message: String) = println(name + " says " + message)
      def id(): String = name
    }
    class Employee(override val name: String, val number: Int) extends Person(name) {
      override def talk(message: String) {
        println(name + " with number " + number + " says " + message)
      }
      override def id(): String = number.toString()
    }
    
    object App{
      def main(args :Array[String]){
        val employee = new Employee("Yoda", 4)
        employee.talk("Extend or extend not. There is no try.")
      }
    }
    

    无论是在构造器中还是在任何扩展基类的方法里,override关键字都是必需的。

    3. trait

    一个对象可以拥有多种不同的角色。
    可以将Scala的trait看成是Java的接口外加一个接口的实现。
    也可以将trait看成是一个部分类的实现。

    class Person(val name :String)
    
    trait Nice {
      def greet() = println("Howdily doodily.")  
    }
    
    class Character(override val name :String) extends Person(name) with Nice
    
    object App{
      def main(args : Array[String]){
        val flanders = new Character("Ned")
        flanders.greet
      }
    }
    

    5.2.7 第一天我们学到了什么

    Scala的静态类型是可以推断出来的,用户无需在任何场合都显示声明变量的类型,因为Scala经常可以根据语法线索推断出这些类型。
    编译器也可以强制类型转换,在合理的情况下,编译器还允许隐式类型转换。

    Scala不支持类方法,而是使用了一种称为伙伴对象的概念将同一个类的类方法和实例方法混在一起。

    5.3 第二天:修建灌木丛和其他新把戏

    //单行方法定义
    scala> def double(x:Int):Int = x * 2
    double: (x: Int)Int
    
    scala> double(4)
    res0: Int = 8
    

    def关键字既可以定义函数也可以定义方法。

    //块形式
    scala> def double(x :Int):Int = {
         |     x * 2
         | }
    double: (x: Int)Int
    
    scala> double(6)
    res0: Int = 12
    

    在返回类型Int后面的=是必需的。漏掉的话会出错。

    5.3.1 对比varval

    scala> var mutable = "I am mutable"
    mutable: String = I am mutable
    
    scala> mutable = "Touch me, change me..."
    mutable: String = Touch me, change me...
    
    scala> val immutable = "I am not mutable"
    immutable: String = I am not mutable
    
    scala> immutable = "Can't touch this"
    <console>:12: error: reassignment to val
           immutable = "Can't touch this"
                     ^
    

    var变量的值是可变的,而val变量的值是不变的。
    在控制台中,为方便起见,你可以多次重复定义一个变量,即使你使用的是val。一旦你脱离控制台,重定义变量会引发一个错误。
    Scala引入var风格变量以支持传统的命令式编程风格,但是要避免使用var
    可变状态限制并发。

    5.3.2 集合

    函数式编程语言因其甚为好用的集合操作而闻名已久。

    列表

    scala> List(1, 2, 3)
    res1: List[Int] = List(1, 2, 3)
    
    scala> List("one", "tow", "three")
    res2: List[String] = List(one, tow, three)
    
    scala> List("one", "tow", 3)
    res3: List[Any] = List(one, tow, 3)
    
    scala> List("one", "tow", 3)(2)
    res4: Any = 3
    
    scala> List("one", "tow", 3)(4)
    java.lang.IndexOutOfBoundsException: 4
      at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
    )
      at scala.collection.immutable.List.apply(List.scala:84)
      ... 32 elided
    

    列表访问是一个函数,所以使用的是()而不是[]

    scala> List("one", "tow", 3)(-1)
    java.lang.IndexOutOfBoundsException: -1
      at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
    )
      at scala.collection.immutable.List.apply(List.scala:84)
      ... 32 elided
    
    scala> List("one", "tow", 3)(-2)
    java.lang.IndexOutOfBoundsException: -2
      at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
    )
      at scala.collection.immutable.List.apply(List.scala:84)
      ... 32 elided
    
    scala> List("one", "tow", 3)(-3)
    java.lang.IndexOutOfBoundsException: -3
      at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
    )
      at scala.collection.immutable.List.apply(List.scala:84)
      ... 32 elided
    

    用负数作为下标,早期的Scala版本会返回列表的第一个元素。但是这种行为与表示下标值过大的异常NoSuchElement不一致,所以2.8.0版本修改了这种行为,让它返回java.lang.IndexOutOfBoundsException异常。
    Nil是一个空列表。

    scala> Nil
    res9: scala.collection.immutable.Nil.type = List()
    

    2.集

    scala> val animals = Set("lions", "tigers", "bears")
    animals: scala.collection.immutable.Set[String] = Set(lions, tigers, bears)
    
    scala> animals + "armadillos"
    res10: scala.collection.immutable.Set[String] = Set(lions, tigers, bears, armadillos)
    
    scala> animals - "tigers"
    res11: scala.collection.immutable.Set[String] = Set(lions, bears)
    
    scala> animals + Set("armadillos", "raccoons")
    <console>:13: error: type mismatch;
     found   : scala.collection.immutable.Set[String]
     required: String
           animals + Set("armadillos", "raccoons")
                        ^
    

    集操作是没有破坏性的。每个集操作都会建立一个新的集而不是修改旧的集。默认情况下,集是不可改变的。

    scala> animals ++ Set("armadillos", "raccoons")
    res13: scala.collection.immutable.Set[String] = Set(bears, tigers, lions, armadillos, raccoons)
    
    scala> animals -- Set("lions", "bears")
    res14: scala.collection.immutable.Set[String] = Set(tigers)
    

    交集

    scala> animals & Set("armadillos", "raccoons", "lions", "tigers")
    res16: scala.collection.immutable.Set[String] = Set(lions, tigers)
    

    与列表不同,集与次序无关。

    scala> Set(1, 2, 3) == Set(3, 2, 1)
    res17: Boolean = true
    
    scala> List(1, 2, 3) == List(3, 2, 1)
    res18: Boolean = false
    

    映射

    scala> val ordinals = Map(0 -> "zero", 1 -> "one", 2 -> "tow")
    ordinals: scala.collection.immutable.Map[Int,String] = Map(0 -> zero, 1 -> one,
    2 -> tow)
    
    scala> ordinals(2)
    res19: String = tow
    
    scala> import scala.collection.mutable.HashMap
    import scala.collection.mutable.HashMap
    
    scala> val map = new HashMap[Int, String]
    map: scala.collection.mutable.HashMap[Int,String] = Map()
    
    scala> map += 4 -> "four"
    res20: map.type = Map(4 -> four)
    
    scala> map += 8 -> "eight"
    res21: map.type = Map(8 -> eight, 4 -> four)
    
    scala> map
    res22: scala.collection.mutable.HashMap[Int,String] = Map(8 -> eight, 4 -> four)
    
    scala> map += "zeor" -> 0
    <console>:14: error: type mismatch;
     found   : (String, Int)
     required: (Int, String)
           map += "zeor" -> 0
                         ^
    

    4.Any和Nothing

    所有类都继承自Any,并且Nothing类继承自所有类。

    Any和Nothing

    5.3.3 集合与函数

    高阶函数:一个以其他函数作为输入参数或以函数作为返回结果的函数。

    1.foreach

    //代码块
    variableName => yourCode
    
    scala>  val list = List("frodo", "samwise", "pippin")
    list: List[String] = List(frodo, samwise, pippin)
    
    scala> list.foreach(hobbit => println(hobbit))
    frodo
    samwise
    pippin
    
    scala> val hobbits = Set("frodo", "samwise", "pippin")
    hobbits: scala.collection.immutable.Set[String] = Set(frodo, samwise, pippin)
    
    scala> hobbits.foreach(hobbit => println(hobbit))
    frodo
    samwise
    pippin
    
    scala> val hobbits = Map("frodo" -> "hobbit", "samwise" -> "hobbit", "pippin" ->
     "hobbit")
    hobbits: scala.collection.immutable.Map[String,String] = Map(frodo -> hobbit, sa
    mwise -> hobbit, pippin -> hobbit)
    
    scala> hobbits.foreach(hobbit => println(hobbit))
    (frodo,hobbit)
    (samwise,hobbit)
    (pippin,hobbit)
    
    scala> hobbits.foreach(hobbit => println(hobbit._1))
    frodo
    samwise
    pippin
    
    scala> hobbits.foreach(hobbit => println(hobbit._2))
    hobbit
    hobbit
    hobbit
    

    2.更多列表方法

    scala> list
    res5: List[String] = List(frodo, samwise, pippin)
    
    scala> list.isEmpty
    res6: Boolean = false
    
    scala> Nil.isEmpty
    res7: Boolean = true
    
    scala> list.length
    res8: Int = 3
    
    scala> list.size
    res9: Int = 3
    

    获取列表的头和尾对递归非常有用。

    scala> list.head
    res10: String = frodo
    
    scala> list.tail
    res11: List[String] = List(samwise, pippin)
    
    scala> list.last
    res12: String = pippin
    
    scala> list.init
    res13: List[String] = List(frodo, samwise)
    
    scala> list
    res14: List[String] = List(frodo, samwise, pippin)
    
    scala> list.reverse
    res15: List[String] = List(pippin, samwise, frodo)
    
    scala> list.drop(1)
    res16: List[String] = List(samwise, pippin)
    
    scala> list
    res17: List[String] = List(frodo, samwise, pippin)
    
    scala> list.drop(2)
    res18: List[String] = List(pippin)
    

    3.计数、映射、过滤以及其他

    scala> val words = List("peg", "al", "bud", "kelly")
    words: List[String] = List(peg, al, bud, kelly)
    
    scala> words.count(word => word.size > 2)
    res19: Int = 3
    
    scala> words.filter(word => word.size > 2)
    res20: List[String] = List(peg, bud, kelly)
    
    scala> words.map(word => word.size)
    res21: List[Int] = List(3, 2, 3, 5)
    
    scala> words.forall(word => word.size > 1)
    res22: Boolean = true
    
    scala> words.exists(word => word.size > 4)
    res23: Boolean = true
    
    scala> words.exists(word => word.size > 5)
    res24: Boolean = false
    
    scala> words.sortWith((s, t) => s.size < t.size)
    res32: List[String] = List(al, peg, bud, kelly)
    

    4. foldLeft

    floadLeft会将数组中的每个元素和另外的一个值传递给代码块。另外的值可以是初始值(在第一次调用代码块时)也可以是从代码块中返回的结果。

    initialValue /: List codeBlock
    scala> words.sortWith((s, t) => s.charAt(0).toLower < t.charAt(0).toLower)
    res34: List[String] = List(al, bud, kelly, peg)
    
    scala> val sum = (0 /: list) {(sum, i) => sum + i}
    sum: Int = 6
    
    柯里化

    函数式编程语言使用柯里化将一个带有多个参数的函数转换为多个拥有独立参数列表的函数。

    scala> val list = List(1, 2, 3)
    list: List[Int] = List(1, 2, 3)
    
    scala> list.foldLeft(0)((sum, value) => sum + value)
    res35: Int = 6
    

    5.3.4 第二天我们都学到了什么

    编译器尝尝能推断出函数的返回类型,函数定义有单行和代码块两种形式,并且参数列表可以改变。。

    5.4 第三天:剪断绒毛

    5.4.1 XML

    Scala将XML抬高到语言的一等编程结构。

    scala> var movies =
         | <movies>
         |     <movie genre="action">Pirates of the Caribbean</movie>
         |     <movie genre="fairytale">Edward Scissorhands</movie>
         | </movies>
    movies: scala.xml.Elem =
    <movies>
        <movie genre="action">Pirates of the Caribbean</movie>
        <movie genre="fairytale">Edward Scissorhands</movie>
    </movies>
    
    scala> movies.text
    res36: String =
    "
        Pirates of the Caribbean
        Edward Scissorhands
    "
    

    Scala内置了一种与XPath类似的查询语言,XPath是一种XML查询语言。不过由于在Scala中,关键字//是注释的修饰符,Scala将使用\\\

    scala> val movieNodes = movies \ "movie"
    movieNodes: scala.xml.NodeSeq = NodeSeq(<movie genre="action">Pirates of the Caribbean</movie>, <movie genre="fairytale">Edward Scissorhands</movie>)
    
    scala> val movieNodes = movies \\ "movie"
    movieNodes: scala.xml.NodeSeq = NodeSeq(<movie genre="action">Pirates of the Caribbean</movie>, <movie genre="fairytale">Edward Scissorhands</movie>)
    
    scala> movieNodes(0)
    res37: scala.xml.Node = <movie genre="action">Pirates of the Caribbean</movie>
    
    scala> movieNodes(0) \ "@genre"
    res38: scala.xml.NodeSeq = action
    
    

    5.4.2 模式匹配

    
    object App{
      def doChore(chore: String): String = chore match {
        case "clean dishes" => "scrub, dry"
        case "cook dinner" => "chop, sizzle"
        case _ => "whine, complain"//_是一个通配符
      }
      def main(args : Array[String]){
          println(doChore("clean dishes"))
        println(doChore("mow lawn"))
      }
    }
    

    1.哨兵

    
    object App{
      def factorial(n: Int): Int= n match {
        case 0 => 1
        case x if x > 0 => factorial(n - 1) * n
      }
      def main(args : Array[String]){
          println(factorial(3))
          println(factorial(0))
      }
    }
    

    2.正则表达式

    Scala中的正则表达式是一等类型。针对一个字符串的.r方法可以将任意字符串转换成正则表达式。

    scala> val reg = """^(F|f)\w*""".r
    reg: scala.util.matching.Regex = ^(F|f)\w*
    
    scala> println(reg.findFirstIn("Fantastic"))
    Some(Fantastic)
    
    scala> println(reg.findFirstIn("not Fantastic"))
    None
    

    """为字符串划定界限,允许多行字符串,去除了其内部字符串的求职过程。.r方法将字符串转换为正则表达式。

    scala> val reg = "the".r
    reg: scala.util.matching.Regex = the
    
    scala> reg.findAllIn("the way the scissors trim the hair and the shrubs")
    res41: scala.util.matching.Regex.MatchIterator = non-empty iterator
    
    scala> val matchs = reg.findAllIn("the way the scissors trim the hair and the shrubs")
    matchs: scala.util.matching.Regex.MatchIterator = non-empty iterator
    
    scala> matchs.foreach(it => println(it))
    the
    the
    the
    the
    
    

    3.XML和匹配

    import scala.xml
      
    object App{
      def main(args : Array[String]){
        val movies = <movies>
                <movie>The Incredibles</movie>
                <movie>WALL E</movie>
                <short>Jack Jack Attack</short>
            <short>Geri's Game</short>
        </movies>
        (movies \ "_").foreach{ movie => 
          movie match {
            case <movie>{movieName}</movie> => println(movieName)
            case <short>{shortName}</short> => println(shortName + "(short)" )
          }    
        }
      }
    }
    

    5.4.3 并发

    包括actor和消息传递。actor拥有线程池和队列池。当发送一条消息给actor时(使用!操作符),是将一个对象放到该actor的队列中。actor读取消息并采取行动。通常情况下,actor通过模式匹配器去检测消息并执行相应的消息处理。

    import scala.actors.Actor
    
    case object Poke
    case object Feed
    
    class Kid() extends Actor {
      def act() = {
        loop {
          react {
            case Poke => {
                println("Ow...")
                Thread.sleep(2000)
              println("Quit it...")
            }
            case Feed => {
                println("Gurgle...")
                Thread.sleep(2000)
              println("Burp...")
            }
          }
        }
      }
    }
    object App {
      def main(args: Array[String]) {
          val bart = new Kid().start
        val lisa = new Kid().start
        bart ! Poke
        lisa ! Poke
        bart ! Feed
        lisa ! Feed
      }
    }
    

    Kid是actor,这意味着它将在线程池中的某个线程中运行,并从一个队列中读取消息。它将一个接一个地处理每条消息。react可以接收来自actor的消息。

    使用actor,可以设置超时处理(reactWithin),当在指定时间内没有接收到消息时,会触发超时处理。使用receive(它将阻塞线程)和receiveWithin(它将在设置的超时时间内阻塞线程)。

    5.4.4 实际中的并发

    import scala.io._
    import scala.actors._
    import Actor._
    
    object App {
      object PageLoader {
        def getPageSize(url: String) = Source.fromURL(url).mkString.length
      }
      val urls = List("http://www.baidu.com/",
                      "http://www.jianshu.com/",
                      "http://www.youdao.com/",
                      "http://www.sina.com.cn/")
      def timeMethod(method: ()=> Unit) = {
        val start = System.nanoTime()
        method()
        val end = System.nanoTime()
        println("Method took " + (end - start)/1000000000.0 + " seconds." )
      }
      
      def getPageSizeSequentially() = {
        for (url <- urls) {
          println("Size for " + url + ":" + PageLoader.getPageSize(url))
        }
      }
      
      def getPageSizeConcurrently() = {
        val caller = self
        
        for (url <- urls) {
          actor { caller !(url, PageLoader.getPageSize(url))}
        }
        
        for (i <- 1 to urls.size) {
          receive {
            case (url, size) => 
              println("Size for " + url + ": " + size)
          }
        }
      }
      def main(args: Array[String]) {
          println("Sequential run:")
          timeMethod{getPageSizeSequentially}
          
        println("Concurrent run:")
        timeMethod{getPageSizeSequentially}
        
        
      }
    }
    

    5.4.5 第三天我们学到了什么

    actor是为并发而构建出来的对象。通常拥有一个包含reactreceive方法的循环,用于接收发给该对象的队列消息。

    5.5 趁热打铁

    Scala使用的是静态类型策略。

    5.5.1核心优势

    1.并发

    无需可变状态的并发应用设计能力
    不变性是为改善并发代码设计能够做的唯一的、最重要的事情。

    2. 遗留Java的演化

    Scala应用可以直接使用Java库,并且在必要时可以使用代理对象的代码生成功能,与Java的互操作行非常好。
    创立新的编程社区的最好方法就是充分接受现有的社区。
    代码块成为了语言的一等类型构造,并且可以与核心集合库很好地集成在一起使用。

    3. 领域特定语言

    Scala灵活语法和操作符重载
    操作符只是简单的方法声明

    4.XML

    Scala提供内置的XML支持。模式匹配使得各种不同的XML结构的解析块易于使用。将XPath语法集成到复杂的XML中使得代码变得更为简单、可读。

    5.桥接

    函数式编程模式很重要,因为它可以很好地处理并发,并且处理器的并发程度也越来越高。

    5.5.2 不足之处

    Scala的语法要求过多且偏学术性。

    1. 静态类型

    静态类型天生适合函数式编程语言,但是对于面向对象系统就是灾难

    2.语法

    构造器 new Person而不是Person.new
    参数类型setName(name: String)而不是setName(String name)
    返回类型从Java方法声明的开头处挪到了结尾处。

    3. 可变性

    可变性可能导致各种各样的并发bug。

    5.5.3 最后思考

    相关文章

      网友评论

        本文标题:《七周七语言:理解多种编程范型 第5章 Scala》笔记

        本文链接:https://www.haomeiwen.com/subject/znsujttx.html