快学scala 第十一章 操作符 读书笔记及习题答案代码

chapter 11 操作符

标签:快学scala


一、笔记

  1. scala种可以在反引号中包含几乎任何字符序列,
  1. val ‘val‘ = 42

所有的操作符都是左结合的,除了以冒号(:)结尾的操作符,和赋值操作符。用于构造列表的::操作符是又结合的。1::2::Ni1的意思是1::(2::Ni1),先创建出包含2的列表,这个列表又被作为尾巴拼接到以1作为头部的列表中。

2. 函数调用语法:f(arg1, arg2,...)扩展到可以应用于函数之外的值,如果f不是函数或方法,那么这个表达式等于f.apply(arg1,arg2,....)。除非它出现在赋值语句的等号左侧。

  1. f(arg1,arg2,...) = value 等同于如下调用
  2. f.update(arg1,arg2,....,value)
  1. 提取器是一个unapply方法的对象,可以把unapply方法当做是伴生对象中apply方法的方向操作。apply接受构造参数,然后将它们变成对象,unapply方法接受一个对象,然后从中提取值,通常这些值就是当初用来构造该对象的值。

    unapply方法返回的是一个Option,它包含一个元组,每个匹配到的变量各有一个值与之对应。

  1. object Fraction{
  2. def unapply(input: Fraction)=
  3. if(input.den == 0) None else Some((input.num, input.den))
  4. } //方法在分母为0时返回None,表示无匹配。
  1. 要提取任意长度的值的序列,我们应该用unapplySeq来命名我们的方法,它返回一个Option[Seq[A]],其中A是被提取的值的类型。比如,Name提取器可以产出名字中所有组成部分的序列:
  1. object Name{
  2. def unapplySeq(input: String): Option[Seq[A]] =
  3. if(input.trim == "") None else Some(input.trim.split("\\s+"))
  4. }
  5. //匹配任意数量的变量
  6. author match{
  7. case Name(first, last) =>..
  8. case Name(first, middle,last)=>..
  9. ...
  10. }

二、习题答案

11.1 根据优先级规则,3 + 4 -> 5和3 -> 4 + 5是如何被求值的?

都是从左至右执行,所以 3 -> 4 + 5表达式是不合法的。

11.2 BigInt类有一个pow方法,但没有用操作符字符。Scala类库的设计者为什么没有选用**(像Fortran那样)或者^(像Pascal那样)作为乘方操作符呢?

scala中操作符就是方法,优先级是根据首字母来判断的。
  1. 最高优先级:除以下字符外的操作符字符
  2. * / %
  3. + -
  4. :
  5. = !
  6. < >
  7. &
  8. ?
  9. |
  10. 非操作符
  11. 最低优先级:赋值操作符
一般乘方操作符优先于乘法操作,如果使用**作为乘方的话,那么其优先级则与*相同,而如果使用^的话,则优先级低于*操作。优先级都是有问题的。故没有使用这两种操作符。

11.3 实现Fraction类,支持+*/操作。支持约分,例如将15/-6变为-5/2。除以最大公约数,像这样:

  1. class Fraction(n:Int,d:Int){
  2. private val num:Int = if(d==0) 1 else n * sign(d)/gcd(n,d);
  3. private val den:Int = if(d==0) 0 else d * sign(d)/gcd(n,d);
  4. override def toString = num + "/" + den
  5. def sign(a:Int) = if(a > 0) 1 else if (a < 0) -1 else 0
  6. def gcd(a:Int,b:Int):Int = if(b==0) abs(a) else gcd(b,a%b)
  7. ...
  8. }
  1. import scala.math.abs
  2. class Fraction(n: Int, d: Int){
  3. private val num: Int = if(d == 0)1 else n *sign(d)/gcd(n,d)
  4. private val den: Int = if(d == 0)0 else d * sign(d)/gcd(n,d)
  5. override def toString = num + "/" +den
  6. def sign(a: Int) = if(a >0)1 else if(a <0) -1 else 0
  7. def gcd(a: Int, b: Int): Int = if(b == 0) abs(a) else gcd(b, a%b)
  8. def +(other: Fraction): Fraction= {
  9. new Fraction((this.num * other.den) + (other.num *this.den), this.den * other.den)
  10. }
  11. def -(other: Fraction): Fraction={
  12. new Fraction((this.num * other.den) - (other.num *this.den), this.den * other.den)
  13. }
  14. def *(other: Fraction): Fraction={
  15. new Fraction(this.num * other.num, this.den * other.den)
  16. }
  17. def / (other: Fraction): Fraction={
  18. new Fraction(this.num * other.den, this.den * other.num)
  19. }
  20. }
  21. object Fraction{
  22. def apply(n: Int, d: Int) = new Fraction(n, d)
  23. }
  24. val x = Fraction(15, -6)
  25. val y = Fraction(20,60)
  26. println(x)
  27. println( x + y)
  28. println( x * y)

11.4 实现一个Money类,加入美元和美分字段。提供+,-操作符以及比较操作符==和<。举例来说,Money(1,75)+Money(0,50)==Money(2,25)应为true。你应该同时提供*和/操作符吗?为什么?

  1. class Money(d: BigInt, c: BigInt) extends Ordered[Money]{
  2. val dollars: BigInt = d + c /100
  3. val cents: BigInt = c % 100
  4. override def toString() = "%d.%d".format(dollars, cents)
  5. def toCents(): BigInt = dollars * 100 + cents
  6. def fromCents(cents: BigInt) = new Money(cents / 100, cents % 100)
  7. override def compare(that: Money): Int = toCents.compare(that.toCents)
  8. def + (that: Money) = fromCents(this.toCents + that.toCents)
  9. def - (that: Money) = fromCents(this.toCents - that.toCents)
  10. }
  11. object Money{
  12. def apply(d: Int, c: Int) = new Money(d, c)
  13. }
  14. val x = Money(1, 75)
  15. val y = Money(0, 50)
  16. println(x + y)
  17. println(x - y)
  18. println(x > y) //true

11.5 提供操作符用于构造HTML表格。例如:Table() | "Java" | "Scala" || "Gosling" | "Odersky" || "JVM" | "JVM,.NET"应产出

  1. :<table><tr><td>Java</td></tr><td>Scala</td></tr><tr><td>Gosling…
  1. import collection.mutable.ArrayBuffer
  2. class Table{
  3. private val chunks = new ArrayBuffer[String]
  4. def | (chunk: String)= {
  5. chunks += "<td>%s</td>\n".format(chunk)
  6. this
  7. }
  8. def ||(chunk: String) = {
  9. chunks += "</tr><tr>\n<td>%s</td>".format(chunk)
  10. this
  11. }
  12. override def toString = "<table><tr>\n%s</tr><table".format(chunks.mkString)
  13. }
  14. object Table{
  15. def apply() = new Table()
  16. }
  17. val t = Table() | "Java" | "Scala" || "Gosling" | "Odersky" || "JVM" | "JVM,.NET"
  18. println(t)

11.6 提供一个ASCIIArt类,其对象包含类似这样的图形:

  1. /\_/\
  2. ( ‘ ‘ )
  3. ( - )
  4. | | |
  5. (__|__)
  6. 提供将两个ASCIIArt图形横向或纵向结合的操作符。选用适当优先级的操作符命名。纵向结合的实例
  7. /\_/\ -----
  8. ( ‘ ‘ ) / Hello \
  9. ( - ) < Scala |
  10. | | | \ Coder /
  11. (__|__) -----
  1. class ASCIIArt(val art: String){
  2. def +(other: ASCIIArt) = new ASCIIArt(
  3. art.split("\n").zip(other.art.split("\n")).map(x => x._1 + x._2).mkString("\n")
  4. )
  5. def ^(other: ASCIIArt) = new ASCIIArt( art + "\n" + other.art)
  6. override def toString = art
  7. }
  8. val x = new ASCIIArt(
  9. """ /\_/\
  10. ( ‘ ‘ )
  11. ( - )
  12. | | |
  13. (__|__)""")
  14. val y = new ASCIIArt(
  15. """ -----
  16. / Hello \
  17. < Scala |
  18. \ Coder /
  19. -----""")
  20. println(x + y)
  21. println(x ^ y)

11.7 实现一个BigSequence类,将64个bit的序列打包在一个Long值中。提供apply和update操作来获取和设置某个具体的bit

  1. class BitSequence(private var value: Long = 0){
  2. implicit def bool2int(b: Boolean) = if(b) 1 else 0
  3. def update(bit: Int, state: Int) = value |= (state & 1L)<< bit % 64
  4. def apply(bit: Int): Int = if((value & 1L << bit % 64) > 0) 1 else 0
  5. override def toString = "%64s".format(value.toBinaryString).replace(" ", "0")
  6. }
  7. val x = new BitSequence()
  8. x(5) = 1
  9. x(63) = 1
  10. x(64) = 1
  11. println(x(5))
  12. println(x)

11.8 提供一个Matrix类—你可以选择需要的是一个2*2的矩阵,任意大小的正方形矩阵,或m*n的矩阵。支持+和操作。操作应同样适用于单值,例如mat*2。单个元素可以通过mat(row,col)得到

  1. class Matrix(val m: Int, val n: Int){
  2. private val value = Array.ofDim[Double](m, n)
  3. def update(x: Int, y: Int, v: Double) = value(x)(y) = v
  4. def apply(x: Int, y: Int) = value(x)(y)
  5. def +(other: Matrix) = {
  6. require (n == other.n)
  7. require (m == other.m)
  8. var res = new Matrix(m,n)
  9. for(i <- 0 until m; j <- 0 until n){
  10. res(i, j) = this.value(i)(j) + other.value(i)(j)
  11. }
  12. res
  13. }
  14. def *(factor: Double) = {
  15. var res = new Matrix(m, n)
  16. for(i <- 0 until m; j <- 0 until n) {
  17. res(i, j) = this.value(i)(j) * factor
  18. }
  19. res
  20. }
  21. private def prod(other: Matrix, i: Int, j: Int) = {
  22. (for (k <- 0 until n) yield value(i)(k) * other.value(j)(k)).sum
  23. }
  24. def *(other: Matrix) = {
  25. require(n == other.m)
  26. var res = new Matrix(m, n)
  27. for(i <- 0 until m; j <- 0 until n) {
  28. res(i, j) = prod(other, i, j)
  29. }
  30. res
  31. }
  32. override def toString = value.map(_.mkString(" ")).mkString("\n")
  33. }
  34. val x = new Matrix(2,3)
  35. x(0, 0) = 1
  36. x(0, 0) = 1
  37. x(1, 0) = 3
  38. x(1, 1) = 4
  39. println(x)
  40. println()
  41. println(x * 2)
  42. println()

11.9 为RichFile类定义unapply操作,提取文件路径,名称和扩展名。举例来说,文件/home/cay/readme.txt的路径为/home/cay,名称为readme,扩展名为txt

  1. object RichFile{
  2. def unapply(s: String) = {
  3. val pos = s.lastIndexOf("/")
  4. if(pos == -1) None else Some((s.substring(0, pos), s.substring(pos+1)))
  5. }
  6. }
  7. val RichFile(path, name) = "/home/user/scala/test.txt"
  8. println("Path: %s, File: %s".format(path, name))

11.10 为RichFile类定义一个unapplySeq,提取所有路径段。举例来说,对于/home/cay/readme.txt,你应该产出三个路径段的序列:home,cay和readme.txt

  1. object RichFile {
  2. def unapplySeq(s: String): Option[Seq[String]] = {
  3. if (s.trim == "") None else Some(s.trim.split("/"))
  4. }
  5. }
  6. val RichFile(first, middle, last) = "home/user/text.txt"
  7. println("First: %s, Middle: %s, Last: %s".format(first, middle, last))
时间: 2024-10-23 03:04:28

快学scala 第十一章 操作符 读书笔记及习题答案代码的相关文章

c++ primer(第五版)学习笔记及习题答案代码版(第十四章)重载运算与类型转换

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.h 和.cc 中,需要演示某一题直接修改 #define NUM****, 如运行14.30题为#define NUM1430: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful f

快学Scala第13章----集合

本章要点 所有集合都扩展自Iterable特质 集合有三大类:序列.集.映射 对于几乎所有集合类,Scala都同时提供了可变的和不可变的版本 Scala列表要么是空的,要么拥有一头一尾,其中尾部本身又是一个列表 集是无先后次序的集合 用LinkedhashSet 来保留插入顺序,或者用SortedSet来按顺序进行迭代 '+' 将元素添加到无先后次序的集合中: +: 和 :+ 向前或向后追加到序列: ++将两个集合串接在一起: -和–移除元素 Iterable和Seq特质有数十个用于常见操作的方

快学Scala第10章----特质

本章要点 类可以实现任意数量的特质 特质可以要求实现它们的类具备特定的字段.方法或超类 和Java接口不同,Scala特质可以提供方法和字段的实现 当你将多个特质叠加在一起时,顺序很重要--其方法先被执行的特质排在更后面 为什么没有多重继承 Scala和Java一样不允许类从多个超类继承:从多了超类继承可能会导致许多问题,例如两个超类有相同的方法,子类该如何使用和菱形继承.在java 中类只能扩展自一个超类,它可以实现任意数量的接口,但接口只能包含抽象方法,不能包含字段. Scala提供了特质(

快学Scala第14章----模式匹配和样例类

本章要点 match表达式是一个更好的switch,不会有意外掉入到下一个分支的问题. 如果没有模式能够匹配,会抛出MatchError.可以用case _ 模式来避免. 模式可以包含一个随意定义的条件,称作守卫. 你可以对表达式的类型进行匹配:优先选择模式匹配而不是isInstanceOf/asInstanceOf. 你可以匹配数组.元组和样例类的模式,然后将匹配到的不同部分绑定到变量. 在for表达式中,不能匹配的情况会被安静的跳过. 样例类继承层级中的公共超类应该是sealed的. 用Op

快学Scala 第13章 集合 - 练习解答

1. 编写一个函数,给定字符串,产出一个包含所有字符的下标的映射.举例来说:indexes("Mississippi")应返回一个映射,让'M'对应集{0},'i'对应集{1,4,7,10},依此类推. 使用字符到可变集的映射.另外,你如何保证集是经过排序的? 回答:使用SortedSet可以保证集是经过排序的. package ex13_01 import scala.collection.mutable.SortedSet import scala.collection.mutab

快学Scala 第十一课 (类继承)

类继承: class People { } class Emp extends People{ } 和Java一样,final的类不能被继承.final的字段和方法不能被override. 在Scala中重写一个非抽象方法必须使用override, 继承抽象方法前面加了override也没关系. abstract class Person { def say(s: String): Unit } class Worker extends Person{ override def say(s: S

快学Scala 第6章 对象 - 练习

1. 编写一个Conversions对象,加入inchesToCentimeters.gallonsToLiters和milesToKilometers方法. object Conversions {     def main(args: Array[String]){         printf("1 inch = %g centimeters\n", inchesToCentimeters(1))         printf("2 gallons = %g liter

快学Scala 第18章 高级类型 习题解答

1. 实现一个Bug类,对沿着水平线爬行的虫子建模.move方法向当前方向移动,turn方法让虫子转身,show方法打印出当前的位置.让这些方法可以被串接调用.例如: bugsy.move(4).show().move(6).show().turn().move(5).show() 上述代码应显示 4 10 5. package ex18_01 class Bug {   var x = 0   var y = 0   var curr_direction = 0   def move(len:

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

条件表达式 在Scala中,if/else 表达式是有值的,这个就是跟在if或者else之后的表达式的值.例如: val s = if(x > 0) 1 else -1 // 类似于 var s = 0 if(x > 0) s = 1 else s = -1 Scala允许使用混合类型的返回值,例如: if(x > 0) "positive" else -1 上式表达式返回的类型是它们类型的公共超类型, 在这里java.lang.String 和 Int 它们的公共超