快学scala笔记.

Posted 燃烧的岁月_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快学scala笔记.相关的知识,希望对你有一定的参考价值。

第一章 基础


val 定义的值实际上是一个常量
var 声明其值可变的变量


val xmax,ymax = 100
var greeting,message: String = null


1.3 常用类型
Scala的7种数值类型:Byte、Char、Short、Int、Long、Float和Double


1、toString()
2、to(10)
"Hello".intersect("World")


1.4 算术和操作符重载
val answer = 8 * 5 + 2


scala 提供 += 或者 -=
counter += 1


1.5调用函数和方法
sqrt(2)
pow(2,4)
min(3,Pi)


import scala.math._ //在scala中,_字符是“通配符”,类似Java中的*


BigInt.probablePrime(100,scala.util.Random)


1.6 apply方法
"Hello"(4)


def apply(n: Int): Char
"Hello".apply(4)


def count(p: (Char) => Boolean) : Int


第一章习题
1 简介 
近期对Scala比较感兴趣,买了本《快学Scala》,感觉不错。比《Programming Scala:Tackle Multi-Core Complexity on the Java Virtual Machine》好很多。 是本不错的入门书。而且每个章节都设置了难度级别,每章有习题,可以巩固Scala语法。 
本文的目的就是针对这些习题进行解答 




2 基础 
2.1 在Scala REPL中键入3,然后按Tab键。有哪些方法可以被应用? 
这个。。。。直接操作一遍就有结果了.此题不知是翻译的问题,还是原题的问题,在Scala REPL中需要按3. 然后按Tab才会提示。 直接按3加Tab是没有提示的。下面是结果 
Scala代码   
1. !=             ##             %              &              *              +  
2. -              /              <              <<             <=             ==  
3. >              >=             >>             >>>            ^              asInstanceOf  
4. equals         getClass       hashCode       isInstanceOf   toByte         toChar  
5. toDouble       toFloat        toInt          toLong         toShort        toString  
6. unary_+        unary_-        unary_~        |  


列出的方法并不全,需要查询全部方法还是需要到Scaladoc中的Int,Double,RichInt,RichDouble等类中去查看。 


2.2 在Scala REPL中,计算3的平方根,然后再对该值求平方。现在,这个结果与3相差多少?(提示:res变量是你的朋友) 
依次进行计算即可 
Scala代码   
1. scala> scala.math.sqrt(3)  
2. warning: there were 1 deprecation warnings; re-run with -deprecation for details  
3. res5: Double = 1.7320508075688772  
4.  
5. scala> res5*res5  
6. res6: Double = 2.9999999999999996  
7.  
8. scala> 3 - res6  
9. res7: Double = 4.440892098500626E-16  




2.3 res变量是val还是var? 
val是不可变的,而var是可变的,只需要给res变量重新赋值就可以检测res是val还是var了 
Scala代码   
1. scala> res9 = 3  
2. <console>:8: error: reassignment to val  
3.       res9 = 3  
4.            ^  




2.4 Scala允许你用数字去乘字符串—去REPL中试一下"crazy"*3。这个操作做什么?在Scaladoc中如何找到这个操作? 
Scala代码   
1. scala> "crazy"*3  
2. res11: String = crazycrazycrazy  


从代码可以推断,*是"crazy"这个字符串所具有的方法,但是Java中的String可没这个方法,很明显。此方法在StringOps中。 


2.5 10 max 2的含义是什么?max方法定义在哪个类中? 
直接在REPL中执行 
Scala代码   
1. scala> 10 max 2  
2. res0: Int = 10  
3.  
4. scala> 7 max 8  
5. res1: Int = 8  
6.  
7. scala> 0 max 0  
8. res2: Int = 0  


可以看出,此方法返回两个数字中较大的那个。此方法Java中不存在,所以在RichInt中。 


2.6 用BigInt计算2的1024次方 
简单的API调用 
Scala代码   
1. scala> BigInt(2).pow(1024)  
2. res4: scala.math.BigInt = 1797693134862315907729305190789024733617976978942306572734300811577326758055009631327084773224  
3. 075360211201138798713933576587897688144166224928474306394741243777678934248654852763022196012460941194530829520850057688  
4. 38150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216  




2.7 为了在使用probablePrime(100,Random)获取随机素数时不在probablePrime和Radom之前使用任何限定符,你需要引入什么? 
so easy. import需要的包啊。Random在scala.util中,而probablePrime是BigInt中的方法,引入即可 
Scala代码   
1. import scala.math.BigInt._  
2. import scala.util.Random  
3.  
4. probablePrime(3,Random)  




2.8 创建随机文件的方式之一是生成一个随机的BigInt,然后将它转换成三十六进制,输出类似"qsnvbevtomcj38o06kul"这样的字符串。
查阅Scaladoc,找到在Scala中实现该逻辑的办法。 到BigInt中查找方法。 
Scala代码   
1. scala> scala.math.BigInt(scala.util.Random.nextInt).toString(36)  
2. res21: String = utydx  




2.9 在Scala中如何获取字符串的首字符和尾字符? 
Scala代码   
1. //获取首字符  
2. "Hello"(0)  
3. "Hello".take(1)  
4. //获取尾字符  
5. "Hello".reverse(0)  
6. "Hello".takeRight(1)  




2.10 take,drop,takeRight和dropRight这些字符串函数是做什么用的?和substring相比,他们的优点和缺点都是哪些? 
查询API即可 take是从字符串首开始获取字符串,drop是从字符串首开始去除字符串。 takeRight和dropRight是从字符串尾开始操作。 
这四个方法都是单方向的。 如果我想要字符串中间的子字符串,那么需要同时调用drop和dropRight,或者使用substring 


------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------




第二章 控制结构和函数
2.1 条件表达式
if(x > 0)  1 else -1
val s = if(x > 0) 1 else -1


混合型表达式:
if(x>0) "positive" else -1


2.2 语句终止
val n = 12
if(n>0) { r = r * n; n -= 1}
s = s0 + (v - v0) * t + 0.5 * (a-a0) * t * t


if(n > 0){
 r = r * n
 n -= 1
}


2.3 块表达式和赋值
val distance = { val dx = x - x0; val dy = y - y0; sqrt(dx * dx + dy * dy)}
{ r = r * n; n -= 1}


2.4 输入和输出
print("Answer: ")
println(42)
println("Answer: " + 42)
println("Hello,%s! You are %d years old.\n","Fred",42)


val name = readLine("Your name: ")
print("Your age: ")
val age = readInt()
printf("Hello, %s! Next year,your will be %d.\n",name,age + 1)


2.5 循环
while(n > 0){
    r = r * n
    n -= 1
}




2.6 高级for循环和for推导式
for(i <- 1 to 3; j <- 1 to 3) print((10 * i + j) + " ")
for(i <- -1 to 3;j <- 1 to 3 if i != j) print((10 * i + j) + " ")
for(i <- 1 to 3; from = 4 - i;j <- from to 3) print((10 * i + j) + " ")
for(i <- 1 to 10 yield i % 3)
for(c <- "Hello"; i<- 0 to 1) yield (c + i).toChar
for(i <- 0 to 1;c <- "Hello") yield (c + i).toChar


for{  i<- 1 to 3
      from = 4 -i
      j <- from to 3
}


2.7 函数
def abs(x: Double) = if(x >= 0) x else -x
def fac(n: Int) = {
    var r =1
    for(i <- 1 to n) r = r * i
    r
}


对于递归函数,我们必须指定返回类型。例如:
def fac(n: Int): Int = if (n <= 0) 1 else n * fac(n - 1)


2.8 默认参数和带名参数
def decorate(str: String,left: String = "[",right: String = "]") = left + str + right
decorate(left = "<<<",str = "Hello", right = ">>>")
decorate("Hello",right = "]<<<")


2.9 变长参数
def sum(args: Int*) = {
    var result = 0
    for(arg <- args) result += arg
    result
}
val s = sum(1,4,9,16,25)


val s = sum(1 to 5)


val s = sum(1 to 5: _*)


def recursiveSum(args: Int*): Int = {
    if(args.length == 0) 0
    else args.head + recursiveSum(args.tail: _*)
}


val str = MessageFormat.format("The answer to {0} is {1}")
2.10 过程
Scala 对于不返回值的函数有特殊的表示法。如果函数体包含在花括号当中但没有前面的=号,那么返回类型就是Unit。
这样的函数被称做过程(procedure)。过程不返回值,我们调用它仅仅是为了它的副作用。举例来说,如下过程把一个字符串打印在一个框中,就像这样:
--------
|hello|
--------
由于过程不返回任何值,所以我们可以略去=号
def box(s: String){
    var border = "-" * s.length + "--\n"
    println(border + "|" + s + "|\n" + border)
}


显示声明Unit返回类型
def box(s: String): Unit={
    var border = "-" * s.length + "--\n"
    println(border + "|" + s + "|\n" + border)
}


2.11 懒值
当val被声明为lazy时,它的初始化将被推迟,直到我们首次对它取值。例如,
lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString
懒值对于开销较大的初始化语句而言十分有用。它们还可以应对其他初始化问题,比如循环依赖。
你可以把懒值当做是介于val和def的中间状态。对比如下定义:
//在worlds被定义时被取值
val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString
//在words被首次使用时取值
lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString
//在每一次words被使用时取值
def words = scala.io.Source.fromFile("/usr/share/dict/words").mkString


2.12 异常
Scala异常工作机制和Java或C++一样
throws new IllegalArgumentException("x should not be negative")


if(x >= 0){
    sqrt(x)
} else throw new IllegalArgumentException("x should not be negative")


捕获异常的语法采用的是模式匹配
try{
    process(new URL("http://horstmann.com/fred-tiny.gif"))
} catch{
    case _: MalformedURLException => println("Bad URL:" + url)
    case ex: IOException => ex.printStackTrace()
}


var in = new URL("http://horstman.com/fred.gif").openStream()
try{
    process(in)
} finally {
    in.close()
}


try{...} catch{...} finally{...}
try{try{...} catch{...}} finally {...}




习题:
2 控制结构和函数
2.1 一个数字如果为正数,则它的signum为1;如果是负数,则signum为-1;如果为0,则signum为0.编写一个函数来计算这个值
简单的逻辑判断
def signum(num:Int){if(num>0)print(1)else if(num<0)print(-1)else print(0)}
Scala中已经有此方法了,刚才查找API的时候,应该能看到
BigInt(10).signum
 
2.2 一个空的快表达式{}的值是什么?类型是什么?
在REPL中就能看出来了
scala> val t = {}
t: Unit = ()
可以看出,它的值是()类型是Unit
 
2.2 指出在Scala中何种情况下赋值语句x=y=1是合法的。(提示:给x找个合适的类型定义)
题目已经给了明确的提示了。本章节中已经说过了,在scala中的赋值语句是Unit类型。所以只要x为Unit类型就可以了。
scala> var y=4;
y: Int = 4


scala> var x={}
x: Unit = ()


scala> x=y=7
x: Unit = ()
这也再次证明了{}是Unit类型
 
2.4 针对下列Java循环编写一个Scala版本:
for(int i=10;i>=0;i–)
System.out.println(i);
使用Scala版本改写就OK了
for(i <- 0 to 10 reverse)print(i)
 
2.5 编写一个过程countdown(n:Int),打印从n到0的数字
这个就是将上面的循环包装到过程中而已。还是换个写法吧。
def countdown(n:Int){
    0 to n reverse foreach print
}
 
2.6 编写一个for循环,计算字符串中所有字母的Unicode代码的乘积。举例来说,"Hello"中所有字符串的乘积为9415087488L
scala> var t:Long = 1
t: Long = 1


scala> for(i <- "Hello"){
     | t = t * i.toLong
     | }


scala> t
res57: Long = 9415087488
 
2.7 同样是解决前一个练习的问题,但这次不使用循环。(提示:在Scaladoc中查看StringOps)
scala> var t:Long = 1
t: Long = 1


scala> "Hello".foreach(t *= _.toLong)


scala> t
res59: Long = 9415087488
 
2.8 编写一个函数product(s:String),计算前面练习中提到的乘积
def product(s:String):Long={
    var t:Long = 1
    for(i <- s){
        t *= i.toLong
    }
    t
}
 
2.9 把前一个练习中的函数改成递归函数
配合前一章的take和drop来实现
def product(s:String):Long={
    if(s.length == 1) return s.charAt(0).toLong
    else s.take(1).charAt(0).toLong * product(s.drop(1))
}
 
2.10 编写函数计算xn,其中n是整数,使用如下的递归定义:
? xn=y2,如果n是正偶数的话,这里的y=x(n/2)
? xn = x*x(n-1),如果n是正奇数的话
? x0 = 1
? xn = 1/x(-n),如果n是负数的话
不得使用return语句
def mi(x:Double,n:Int):Double={
    if(n == 0) 1
    else if (n > 0 && n%2 == 0) mi(x,n/2) * mi(x,n/2)
    else if(n>0 && n%2 == 1) x * mi(x,n-1)
    else 1/mi(x,-n)
}


第3章 数组相关操作
本章重点包括:
若长度固定则使用Array,若长度可能有变化则使用ArrayBuffer
提供初始值时不要使用new。
用()来访问元素。
用for(elem <- arr)来遍历元素
用for(elem <- arr if ...)...yield...来将原数组转型为新数组
Scala数组和Java数组可以互操作;用ArrayBuffer,使用scala.collection.JavaConversions中的转换函数。


3.1 定长数组
    val nums = new Array[Int](10)
    val a = new Array[String](10)
    val s = Array("Hello","World")
    s(0) = "Goodbye"


    在JVM中,Scala的Array以Java数组方式实现。
示例中的数组的JVM中的类型为java.lang.String[].Int、Double或其他与Java中基本类型对应的数组都是基本类型数组。举例来说,Array(2,3,5,7,11)


3.2 变长数组:数组缓存


import scala.collection.mutable.ArrayBuffer
val b = ArrayBuffer[Int]()
b += 1
b += (1,2,3,5)
//++=操作符追加任何集合
b ++= Array(8,13,21)
//移除最后5个元素
b.trimEnd(5)


//在下标2之前插入
b.insert(2,6)
//可以插入任意多的元素
b.insert(2,7,8,9)
b.remove(2)
b.remove(2,3)
//构建一个数组缓冲然后调用
b.toArray
//将数组a转换成一个数组缓冲
a.toBuffer


3.3 遍历数组和数组缓冲
for(i <- 0 until b.length)
    println(i + ": " + b(i))
//util是RichInt类的方法,返回所有小于上限的数字。
0 until 10
0 until (b.length,2)


(0 until b.length).reverse
for(elem <- a)
    println(elem)


3.4 数组转换
val a = Array(2,3,5,7,11)
val result = for(elem <- a) yield 2 * elem


for(elem <- a if elem % 2 == 0) yield 2 * elem
a.filter(_ % 2 == 0).map(2 * _)
a.filter{ _ % 2 == 0} map { 2 * _}


var first = true
var n = a.length
var i = 0
while(i < 0){
    if(a(i) >= 0) i+=1
    else 
      if(first){first = false; i += 1}
      else {a.remove(i);n -= 1}
}


var first = true
val indexes = for(i <- 0 until a.length if first || a(i) >= 0) yield{
    if (a(i) < 0) first = false;
    i
}


for(j <- 0 until indexes.length) a(j) = a(indexes(j))
a.trimEnd(a.length - indexes.length)


3.5 常用算法
    Array(1,7,2,9).sum
    ArrayBuffer("Mary","had","a","little","lamb").max


    val b = ArrayBuffer(1,7,2,9)
    val bSorted = b.sorted(_ < _)


    val bDescending = b.sorted(_ > _)
    val a = Array(1,7,2,9)
    scala.util.Sorting.quickSort(a)
    a.mkString(" and ")
    a.mkString("<",",",">")
    a.toString
    b.toString




3.6 解读Scaladoc






3.7 多维数组
    val matrix = Array.ofDim[Double](3,4)
    matrix(row)(column) = 42
    
    val triangle = new Array[Array[Int]](10)
    for(i <- until triangle.length)
      triangle(i) = new Array[Int](i + 1)
3.8 与Java的互操作
import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("ls","-a","/home/cay")
val pb = new ProcessBuilder(command)




import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.mutable.Buffer
val cmd: Buffer[String] = pb.command()


1、编写一段代码,将a设置为一个n个随机整数的数组,要求随机数介于0(包含)和n(不包含)之间。
2、编写一个循环,将整数数组中相邻的元素置换。例如,Array(1,2,3,4,5)经过置换后变为Array(2,1,4,3,5)
3、重复前一个练习,不过这一次生成一个新的值交换过的数组。用for/yield
4、给定一个整数数组,产生一个新的数组,包含元数组中的所有正值,以原有顺序排列,之后的元素是所有零或负值,以原有顺序排序
5、如何计算Array[Double]的平均值?
6、如何重新组织Array[Int]的元素将它们以反序排序?对于ArrayBuffer[Int]你又会怎么做呢?
7、


第4章 映射和元组
4.1 构造映射
4.2 获取映射中的值
4.3 更新映射中的值
4.4 迭代映射
4.5 已排序映射
4.6 与Java的互操作
4.7 元组
    映射是键/值对偶的集合。对偶是元组的最简单形式--元组是不同类型的值得聚集。
    元组的值是通过将单个的值包含在圆括号中构成。例如:
    (1,3,14,"Fred")


    Tuple3[Int,Double,java.lang.String]
    (Int,Double,java.lang.String)


    val t = (1,3,14,"Fred")
    val secnd = t._2


    通常,使用模式匹配来获取元组的组元,例如:
    val (first,second,third) = t //将first设为1,second设为3.14,third设为"Fred"
    val (first,second, _) = t


    "New York".partition(_.isUpper)


4.8 拉链操作
    val symbols = Array("<","-",">")
    val counts = Array(2,10,2)
    val pairs = symbols.zip(counts)


本章的要点包括:
    Scala有十分易用的语法来创建、查询和遍历映射。
    你需要从可变的和不可变的映射中做出选择。
    默认情况下,你得到的是一个哈希映射,不过你也可以指明要树形映射。
    你可以很容易地在Scala映射和Java映射之间来回切换。
    元组可以用来聚集值




4.1 构造映射
    val scores = Map("Alice" -> 10,"Bob" -> 3,"Cindy" -> 8)


    val scores = scala.collection.mutable.Map("Alice" -> 10,"Bob" -> 3,"Cindy" -> 8)


    val scores = new scala.collection.mutable.HashMap[String,Int]


    ->操作符用来创建对偶
    "Alice" -> 10


    上述代码产出的值:
    ()


1、设置一个映射,其中包含你想要的一些装备,以及它们的价格。然后构建另一个映射,采用用一组键,但在价格上9折
2、编写一段程序,从文件中读取单词。用一个可变映射来清点每一个单词出现的频率。读取这些单词的操作可以使用java.util.Scanner:
    val in = new java.util.Scanner(new java.io.File("myfile.txt"))
    while(in.hasNext()) 处理 in.next()
    最后,打印出所有单词和它们出现的次数
3、重复前一个练习,这次用不可变的映射。
4、重复前一个练习,这次用已排序的映射,以便单词可以按顺序打印出来。
5、重复前一个练习,这次用java.util.TreeMap并使之适用于Scala API
6、定义一个链式哈希映射,将“Monday”映射到java.util.Calendar.MONDAY,依次类推加入其他日期。展示元素是以插入的顺序被访问的。
7、打印出所有Java系统属性的表格,类似这样:
    java.runtime.name                  | Java(TM) SE Runtime Environment
    sun.boot.library.path              | /home/apps/jdk 1.6.0.21/jre/lib/i386
    java.vm.version                    | 17.0-bl6
    java.vm.vendor                     | Sun Microsystems Inc
    java.vendor.url                    | http://java.sun.com/
    path.separator                     | :
    java.vm.name                       | Java HotSpot(TM) Server VM


8、编写一个函数
9、编写一个函数
10、当你将两个字符串拉链在一起,比如
11、


第5章
5.1 简单类和无参方法
    class Counter{
      private var value = 0 //
      def increment(){ value += 1}
      def current() = value
    }
    
    val myCounter = new Counter
    myCounter.increment()
    println(myCounter.current)


    myCounter.current
    myCounter.current()


5.2 带getter和setter的属性
5.3 只带getter的属性
5.4 对象私有字段
5.5 Bean属性
    import scala.reflect.BeanProperty
    class Person{
      @BeanProperty var name: String = _
    }
    将会生成四个方法:
      1、name: String
      2、name_=(newValue:String):Unit
      3、getName():String
      4、setName(newValue:String):Unit
      class Person(@BeanProperty var name: String)
5.6 辅助构造器
    class Person{
      private var name = ""
      private var age = 0


      def this(name: String){
        this()
this.name = name
      }


      def this(name: String,age: Int){
        this(name)
this.age = age
      }
    }


    val p1 = new Person
    val p2 = new Person("Fred")
    val p3 = new Person("Fred",42)
5.7 主构造器
    class Person(val name: String,val age: Int){
    
    }


5.8 嵌套类
import scala.collection.mutable.ArrayBuffer
class Network{
    class Member(val name: String){
      val contacts = new ArrayBuffer[Member]
    }
    private val members = new ArrayBuffer[Member]
    def join(name: String) = {
      val m = new Member(name)
      members += m
      m
    }
}


val chstter = new Network
val myFace = new Network


val fred = chatter.join("Fred")
val wilma = chatter.join("Wilma")
fred.contacts += wilma
val barney = myFace.join("Barney")
fred.contacts += barney


object Network{
    class Member(val name: String){
      val contacts = new ArrayBuffer[Member]
    }
}


class Network{
    private val members = new 
}


第七章 包和引入
7.1 包
    package com{
      package horstman{
        package impattern{
 class Employee
}
      }
    }
    package org{
      package bigjava{
        class Counter
      }
    }
7.2 作用域规则
    package com{
      package horstmann{
        object Utils{
 def percentOf(value: Double,rate: Double) = value * rate / 100
 ...
}
      }
    }


    package impatient{
      class Employee{
        def giveRaise(rate: scala.Double){
 salary += Utils.percentOf(salary,rate)
}
      }
    }


7.3 串联式包语句
7.4 文件顶部标记法
7.5 包对象
7.6 包可见性
7.7 引入
7.8 任何地方都可以声明引入
7.9 重命名和隐藏方法
    import java.awt.{Color,Font}


    import java.util.{HashMap => JavaHashMap}
    import scala.collection.mutable._


    import java.util.{HashMap => _,_}
    import scala.collection.mutable._


7.10 隐式引入
    import java.lang._
    import scala._
    import Predef._


    collection.mutable.HashMap
    scala.collection.mutable.HashMap


第8章 继承


8.1 扩展类 
    class Employee extends Person{
      var salary = 0.0
    }
8.2 重写方法
    public class Person{
      override def toString = getClass.getName + "[name=" + name + "]"
    }
8.3 类型检查和转换
    if(p.isInstanceOf[Employee]){
      val s = p.asInstanceOf[Employee]
    }
8.4 受保护字段和方法
8.5 超类的构造
8.6 重写字段
8.7 匿名子类
8.8 抽象类
8.9 抽象字段
8.10 构造顺序和提前定义
8.11 Scala继承层级
8.12 对象相等性







以上是关于快学scala笔记.的主要内容,如果未能解决你的问题,请参考以下文章

快学Scala第2章–控制结构和函数 笔记

[Scala] 快学Scala A2L2

快学Scala

快学Scala课后习题答案

快学Scala--类

快学SCALA(10)--特质