快学Scala习题解答—第十一章 操作符

11 操作符

11.1 依据优先级规则,3 + 4 -> 5和3 -> 4 + 5是怎样被求值的?

在REPL中运行就可以得到结果。都是从左至右运行

12.2 BigInt类有一个pow方法,但没实用操作符字符。

Scala类库的设计者为什么没有选用**(像Fortran那样)或者^(像Pascal那样)作为乘方操作符呢?

Scala中的操作符就是方法。其优先级是依据首字母来推断的,优先级例如以下

最高优先级:除下面字符外的操作符字符

* / %

+ -

:

= !

< >

&

?

|

非操作符

最低优先级:赋值操作符

一般乘方的操作符是优于乘法操作的。假设使用**作为乘方的话,那么其优先级则与*同样。而假设使用^的话,则优先级低于*操作。优先级都是有问题的。故没有使用这两种操作符

11.3 实现Fraction类,支持+*/操作。支持约分,比如将15/-6变为-5/2。

除以最大公约数,像这样:

class Fraction(n:Int,d:Int){

private val num:Int = if(d==0) 1 else n * sign(d)/gcd(n,d);

private val den:Int = if(d==0) 0 else d * sign(d)/gcd(n,d);

override def toString = num + "/" + den

def sign(a:Int) = if(a > 0) 1 else if (a < 0) -1 else 0

def gcd(a:Int,b:Int):Int = if(b==0) abs(a) else gcd(b,a%b)

...

}

import scala.math.abs

class Fraction(n: Int, d: Int) {
  private val num: Int = if (d == 0) 1 else n * sign(d) / gcd(n, d);
  private val den: Int = if (d == 0) 0 else d * sign(d) / gcd(n, d);

  override def toString = num + "/" + den

  def sign(a: Int) = if (a > 0) 1 else if (a < 0) -1 else 0

  def gcd(a: Int, b: Int): Int = if (b == 0) abs(a) else gcd(b, a % b)

  def +(other:Fraction):Fraction={
    newFrac((this.num * other.den) + (other.num * this.den),this.den * other.den)
  }

  def -(other:Fraction):Fraction={
    newFrac((this.num * other.den) - (other.num * this.den),this.den * other.den)
  }

  def *(other:Fraction):Fraction={
    newFrac(this.num * other.num,this.den * other.den)
  }

  def /(other:Fraction):Fraction={
    newFrac(this.num * other.den,this.den * other.num)
  }

  private def newFrac(a:Int,b:Int):Fraction={
    val x:Int = if (b == 0) 1 else a * sign(b) / gcd(a, b);
    val y:Int = if (b == 0) 0 else b * sign(b) / gcd(a, b);
    new Fraction(x,y)
  }
}

object Test extends App{
  val f = new Fraction(15,-6)
  val p = new Fraction(20,60)
  println(f)
  println(p)
  println(f + p)
  println(f - p)
  println(f * p)
  println(f / p)
}

11.4 实现一个Money类,增加美元和美分字段。提供+,-操作符以及比較操作符==和<。

举例来说。Money(1,75)+Money(0,50)==Money(2,25)应为true。

你应该同一时候提供*和/操作符吗?为什么?

class Money(val dollar:BigInt,val cent:BigInt){

  def +(other:Money):Money={
    val (a,b) = (this.cent + other.cent) /% 100
    new Money(this.dollar + other.dollar + a,b)
  }

  def -(other:Money):Money={
    val (d,c) = (this.toCent() - other.toCent()) /% 100
    new Money(d,c)
  }

  private def toCent()={
    this.dollar * 100 + this.cent
  }

  def ==(other:Money):Boolean = this.dollar == other.dollar && this.cent == other.cent

  def <(other:Money):Boolean = this.dollar < other.dollar || (this.dollar == other.dollar && this.cent < other.cent)

  override def toString = "dollar = " + dollar + " cent = " + cent
}

object Money{
  def apply(dollar:Int,cent:Int):Money={
    new Money(dollar,cent)
  }

  def main(args:Array[String]){

    val m1 = Money(1,200)
    val m2 = Money(2,2)
    println(m1 + m2)
    println(m1 - m2)
    println(m1 == m2)
    println(m1 < m2)
    println(Money(1,75)+Money(0,50))
    println(Money(1,75)+Money(0,50)==Money(2,25))

  }
}

不须要提供*和/操作。对于金额来说没有乘除操作

11.5 提供操作符用于构造HTML表格。比如:Table() | "Java" | "Scala" || "Gosling" | "Odersky" || "JVM" | "JVM,.NET"应产出:<table><tr><td>Java</td></tr><td>Scala</td></tr><tr><td>Gosling…

class Table{

  var s:String = ""

  def |(str:String):Table={
    val t = Table()
    t.s = this.s + "<td>" + str + "</td>"
    t
  }

  def ||(str:String):Table={
    val t = Table()
    t.s = this.s + "</tr><tr><td>" + str + "</td>"
    t
  }

  override def toString():String={
    "<table><tr>" + this.s + "</tr></table>"
  }
}

object Table{

  def apply():Table={
    new Table()
  }

  def main(args: Array[String]) {
    println(Table() | "Java" | "Scala" || "Gosling" | "Odersky" || "JVM" | "JVM,.NET")
  }
}

11.6 提供一个ASCIIArt类。其对象包括类似这种图形:

/\_/\

( ‘ ‘ )

(  -  )

| | |

(__|__)

提供将两个ASCIIArt图形横向或纵向结合的操作符。选用适当优先级的操作符命名。

纵向结合的实例

/\_/\     -----

( ‘ ‘ )  / Hello \

(  -  ) <  Scala |

| | |   \ Coder /

(__|__)    -----

import collection.mutable.ArrayBuffer

class ASCIIArt(str:String){
  val arr:ArrayBuffer[ArrayBuffer[String]] = new ArrayBuffer[ArrayBuffer[String]]()

  if (str != null && !str.trim.eq("")){
    str.split("[\r\n]+").foreach{
      line =>
      val s = new ArrayBuffer[String]()
      s += line
      arr += s
    }
  }

  def this(){
    this("")
  }

  def +(other:ASCIIArt):ASCIIArt={
    val art = new ASCIIArt()
    val length = if (this.arr.length >= other.arr.length) this.arr.length else other.arr.length
    for(i <- 0 until length){
      val s = new ArrayBuffer[String]()
      val thisArr:ArrayBuffer[String] = if (i < this.arr.length) this.arr(i) else new ArrayBuffer[String]()
      val otherArr:ArrayBuffer[String] = if (i < other.arr.length) other.arr(i) else new ArrayBuffer[String]()
      thisArr.foreach(s += _)
      otherArr.foreach(s += _)
      art.arr += s
    }
    art
  }

  def *(other:ASCIIArt):ASCIIArt={
    val art = new ASCIIArt()
    this.arr.foreach(art.arr += _)
    other.arr.foreach(art.arr += _)
    art
  }

  override def toString()={
    var ss:String = ""
    arr.foreach{
      ss += _.mkString(" ") + "\n"
    }
    ss
  }
}

object Test extends App{
  val a = new ASCIIArt(""" /\_/                         |( ' ' )
                         |(  -  )
                         | | | |
                         |(__|__)
                         |""".stripMargin)
  val b = new ASCIIArt( """    -----
                          |  / Hello                           | <  Scala |
                          |  \ Coder /
                          |    -----
                          |""".stripMargin)
  println(a + b * b)
  println((a + b) * b)
  println(a * b)
}

11.7 实现一个BigSequence类,将64个bit的序列打包在一个Long值中。

提供apply和update操作来获取和设置某个详细的bit

class BigSequence{
  var num = new Array[Int](64)

  for (i <- 0 until num.length){
    num(i) = -1
  }

  def pack():Long={
    num.filter(_ >= 0).mkString.toLong
  }
}

object BigSequence{

  def apply(num:Int):BigSequence={
    val b = new BigSequence
    var i = 0
    num.toString.foreach{
      n=>
      b.num(i) = n.getNumericValue
      i+=1
    }
    b
  }

  def main(args: Array[String]) {
    val b = BigSequence(10100)
    println(b.pack())
  }
}

11.8 提供一个Matrix类—你能够选择须要的是一个2*2的矩阵。随意大小的正方形矩阵。或m*n的矩阵。

支持+和*操作。*操作应相同适用于单值,比如mat*2。单个元素能够通过mat(row,col)得到

class Matrix(val x:Int,val y:Int){

  def +(other:Matrix):Matrix={
    Matrix(this.x + other.x,this.y + other.y)
  }

  def +(other:Int):Matrix={
    Matrix(this.x + other,this.y + other)
  }

  def *(other:Matrix):Matrix={
    Matrix(this.x * other.x,this.y * other.y)
  }

  def *(other:Int):Matrix={
    Matrix(this.x * other,this.y * other)
  }

  override def toString()={
    var str = ""
    for(i <- 1 to x){
      for(j <- 1 to y){
        str += "*"
      }
      str += "\n"
    }
    str
  }
}

object Matrix{
  def apply(x:Int,y:Int):Matrix= new Matrix(x,y)

  def main(args: Array[String]) {
    val m = Matrix(2,2)
    val n = Matrix(3,4)
    println(m)
    println(n)
    println(m + n)
    println()
    println(m * n)
    println()
    println(m + 2)
    println()
    println(n * 2)
    println()
  }
}

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

class RichFile(val path:String){}
object RichFile{
  def apply(path:String):RichFile={
    new RichFile(path)
  }

  def unapply(richFile:RichFile) = {
    if(richFile.path == null){
      None
    } else {
      val reg = "([/\\w+]+)/(\\w+)\\.(\\w+)".r
      val reg(r1,r2,r3) = richFile.path
      Some((r1,r2,r3))
    }
  }

  def main(args: Array[String]) {
    val richFile = RichFile("/home/cay/readme.txt")
    val RichFile(r1,r2,r3) = richFile
    println(r1)
    println(r2)
    println(r3)
  }
}

11.10 为RichFile类定义一个unapplySeq。提取全部路径段。

举例来说,对于/home/cay/readme.txt。你应该产出三个路径段的序列:home,cay和readme.txt

class RichFile(val path:String){}

object RichFile{
  def apply(path:String):RichFile={
    new RichFile(path)
  }

  def unapplySeq(richFile:RichFile):Option[Seq[String]]={
    if(richFile.path == null){
      None
    } else {
      Some(richFile.path.split("/"))
    }
  }

  def main(args: Array[String]) {
    val richFile = RichFile("/home/cay/readme.txt")
    val RichFile(r @ _*) = richFile
    println(r)
  }
}
时间: 2024-11-05 23:31:47

快学Scala习题解答—第十一章 操作符的相关文章

快学Scala习题解答—第四章 映射和元组

4 映射和元组 4.1 设置一个映射,其中包含你想要的一些装备,以及它们的价格.然后构建另一个映射,采用同一组键,但是价格上打9折 映射的简单操作 Shell代码   scala> val map = Map("book"->10,"gun"->18,"ipad"->1000) map: scala.collection.immutable.Map[java.lang.String,Int] = Map(book ->

快学Scala习题解答—第三章 数组相关操作

3 数组相关操作 3.1 编写一段代码,将a设置为一个n个随机整数的数组,要求随机数介于0(包含)和n(不包含)之间 random和yield的使用 Scala代码   import scala.math.random def randomArray(n:Int)={ for(i <- 0 until n) yield (random * n).toInt } println(randomArray(10).mkString(",")) 3.2 编写一个循环,将整数数组中相邻的元

快学scala习题解答--第五章 类

5 类 5.1 改进5.1节的Counter类,让它不要在Int.MaxValue时变成负数 Scala代码   class Count{ private var value = Int.MaxValue def increment(){if(value < Int.MaxValue) value + 1 else value } def current = value } 5.2 编写一个BankAccount类,加入deposit和withdraw方法,和一个只读的balance属性 Sca

快学Scala习题解答—第一章 基础

1 简介 近期对Scala比较感兴趣,买了本<快学Scala>,感觉不错.比<Programming Scala:Tackle Multi-Core Complexity on the Java Virtual Machine>好很多. 是本不错的入门书.而且每个章节都设置了难度级别,每章有习题,可以巩固Scala语法. 本文的目的就是针对这些习题进行解答 2 基础 2.1 在Scala REPL中键入3,然后按Tab键.有哪些方法可以被应用? 这个....直接操作一遍就有结果了.

快学Scala习题解答—第二章 控制结构和函数

2 控制结构和函数 2.1 一个数字如果为正数,则它的signum为1;如果是负数,则signum为-1;如果为0,则signum为0.编写一个函数来计算这个值 简单的逻辑判断 Scala代码   def signum(num:Int){if(num>0)print(1)else if(num<0)print(-1)else print(0)} Scala中已经有此方法了,刚才查找API的时候,应该能看到 Scala代码   BigInt(10).signum 2.2 一个空的块表达式{}的值

快学Scala习题解答—第八章 继承

8 继承 8.1 扩展如下的BankAccount类,新类CheckingAccount对每次存款和取款都收取1美元的手续费class BankAccount(initialBalance:Double){ private var balance = initialBalance def deposit(amount:Double) = { balance += amount; balance} def withdraw(amount:Double) = {balance -= amount;

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

chapter 11 操作符 标签:快学scala 一.笔记 scala种可以在反引号中包含几乎任何字符序列, val 'val' = 42 所有的操作符都是左结合的,除了以冒号(:)结尾的操作符,和赋值操作符.用于构造列表的::操作符是又结合的.1::2::Ni1的意思是1::(2::Ni1),先创建出包含2的列表,这个列表又被作为尾巴拼接到以1作为头部的列表中. 2. 函数调用语法:f(arg1, arg2,...)扩展到可以应用于函数之外的值,如果f不是函数或方法,那么这个表达式等于f.a

快学Scala课后习题答案

分享一个之前做快学Scala的课后习题(2-21章节,19无)的Github链接,我把习题的文字写在了每个回答的注释上面,这样方便大家对照着看,省的回过头去对照着pdf看了,如果有做的不对的地方希望大家给予指正. 链接如下,http://github.com/fxxkinglife/scala-hello. 举一个第二章节的例子, object charpter02 { /* * 2.1 * 一个数字如果为正数,则它的signum为1; * 如果是负数,则signum为-1; * 如果为0,则s

快学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