《快学Scala》习题详解 第11章 操作符

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


scala> 3+4 -> 5

res0: (Int, Int) = (7,5)

//构成了元组


scala> 3->4+5

<console>:12: error: type mismatch;

 found   : Int(5)

 required: String

       3->4+5

            ^

scala> 3->4+"5"

res4: String = (3,4)5

除赋值外,从左至右操作

2 BigInt类有一个pow方法,但没有用操作符字符。Scala类库的设计者为什么没有选用**(像Fortran那样)或者^(像Pascal那样)作为乘方操作符呢?
因为优先级问题,在scala中*优先于^,但数学中乘方优先于乘法。所以没有提供^作为乘方的操作符

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 math.abs
class Fraction(n: Int, d: Int) {
  val num: Int = if (d == 0) 1 else n * sign(d) / gcd(n, d)
  val den: Int = if (d == 0) 0 else d * sign(d) / gcd(n, d)
  override def toString = num + "/" + den
  //改负数为分子
  def sign(a: Int): 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 +(that: Fraction): Fraction = {
    Fraction((this.num * that.den) + (this.num * that.den), this.den * that.num)
  }
  def -(that: Fraction): Fraction = {
    Fraction((this.num * that.den) - (this.num * that.den), this.den * that.num)
  }
}
object Fraction {
  def apply(a: Int, b: Int) = { new Fraction(a, b) }
}

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

class Money(val m: Double) {
  def +(that: Money): Money = { Money(this.m + that.m) }
  def -(that: Money): Money = { Money(this.m - that.m) }
  def ==(that: Money): Boolean = { if (this.m == that.m) true else false }
}
object Money {
  def apply(m: Double): Money = { new Money(m) }
}
object XX extends App {
  println(Money(3.5) + Money(3.7) == Money(2.0))
}

不应该,无法控制优先级
5 提供操作符用于构造HTML表格。例如:Table() | “Java” | “Scala” || “Gosling” | “Odersky” || “JVM” | “JVM,.NET”应产出

class Table {
  var s: String = ""
  def |(str: String): Table = {
    Table(this.s + "<td>" + str + "</td>")
  }
  def ||(str: String): Table = {
    Table(this.s + "</tr><tr><td>" + str + "</td>")
  }
  override def toString: String = {
    "<table><tr>" + this.s + "</tr></table>"
  }
}
object Table {
  def apply(): Table = {
    new Table
  }
  def apply(str: String): Table = {
    val t = new Table
    t.s = str
    t
  }
}
object Five extends App {
  println(Table() | "Java" | "Scala" || "Gosling" | "Odersky" || "JVM" | "JVM,.NET")
}

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

import scala.collection.mutable.ArrayBuffer

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

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

    def this() {
        this("")
    }

    /**
      * 横向结合
      * @param other
      * @return
      */
    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]()
            // 获取this中的行数据, 行数不足,返回空行
            val thisArr: ArrayBuffer[String] = if (i < this.arr.length) this.arr(i) else new ArrayBuffer[String]()
            // 获取other中的行数据, 行数不足,返回空行
            val otherArr: ArrayBuffer[String] = if (i < other.arr.length) other.arr(i) else new ArrayBuffer[String]()
            // 连接this
            thisArr.foreach(s += _)
            // 连接other
            otherArr.foreach(s += _)
            art.arr += s
        }
        art
    }

    /**
      * 纵向结合
      * @param other
      * @return
      */
    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 Six extends App {
    // stripMargin: "|"符号后面保持原样
    val a = new ASCIIArt(
        """ /\_/\
          |( ' ' )
          |(  -  )
          | | | |
          |(__|__)
          | """.stripMargin)
    val b = new ASCIIArt(
        """   -----
          | / Hello \
          |<  Scala |
          | \ Coder /
          |   -----
          | """.stripMargin)
    println(a + b * b)
    println((a + b) * b)
    println(a * b)
}

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

class BigSequence(private var value: Long = 0) {

    def update(bit: Int, state: Int) = {
        if (state == 1) value |= (state & 1L) << bit % 64
        else value &= ~(1L << bit % 64)
    }

    def apply(bit: Int): Int = if (((value >> bit % 64) & 1L) > 0) 1 else 0

    override def toString = "%64s".format(value.toBinaryString).replace(" ", "0")
}

object Seven {
    def main(args: Array[String]) {
        val x = new BigSequence()
        x(5) = 1
        x(63) = 1
        x(64) = 1

        println(x(5))
        x(64) = 0
        println(x)
    }
}

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

class Matrix(val m: Int, val n: Int) {
    private val value = Array.ofDim[Double](m, n)

    def update(x: Int, y: Int, v: Double) = value(x)(y) = v

    def apply(x: Int, y: Int) = value(x)(y)

    def +(other: Matrix): Matrix = {
        require(n == other.n)
        require(m == other.m)

        val res = new Matrix(m, n)
        for (i <- 0 until m; j <- 0 until n) {
            res(i, j) = this (i, j) + other(i, j)
        }
        res
    }

    def -(other: Matrix): Matrix = {
        this + other * (-1)
    }

    def *(factor: Double): Matrix = {
        val res = new Matrix(m, n)
        for (i <- 0 until m; j <- 0 until n) {
            res(i, j) = this (i, j) * factor
        }
        res
    }

    private def prod(other: Matrix, i: Int, j: Int) = {
        (for (k <- 0 until n) yield value(i)(k) * other.value(j)(k)).sum
    }

    def *(other: Matrix) = {
        require(n == other.m)

        val res = new Matrix(m, other.n)
        for (i <- 0 until m; j <- 0 until other.n) {
            res(i, j) = prod(other, i, j)
        }
        res
    }

    override def toString = value.map(_.mkString(" ")).mkString("\n")
}

object Eight extends App {
    val x = new Matrix(2, 2)
    x(0, 0) = 1
    x(0, 1) = 2
    x(1, 0) = 3
    x(1, 1) = 4
    println(x)
    println()
    println(x * 2)
    println()
    println(x * 2 - x)
    println()
    println((x * 2) * (x * 3))
}

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

class RichFile1(val path: String) {}
object RichFile1 {
  def apply(path: String): RichFile1 = {
    new RichFile1(path)
  }
  def unapply(richFile1: RichFile1) = {
    if (richFile1.path == null) {
      None
    } else {
      val reg = "([/\\w+]+)/(\\w+)\\.(\\w+)".r
      val reg(r1, r2, r3) = richFile1.path
      Some((r1, r2, r3))
    }
  }
}
object Nine {
  def main(args: Array[String]) {
    val richFile1 = RichFile1("/home/cay/readme.txt")
    val RichFile1(r1, r2, r3) = richFile1
    println(r1)
    println(r2)
    println(r3)
  }
}

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

class RichFile2(val path: String) {}
object RichFile2 {
  def apply(path: String): RichFile2 = {
    new RichFile2(path)
  }
  def unapplySeq(richFile2: RichFile2): Option[Seq[String]] = {
    if (richFile2.path == null) {
      None
    } else {
      if (richFile2.path.startsWith("/")) {
        Some(richFile2.path.substring(1).split("/"))
      } else {
        Some(richFile2.path.split("/"))
      }
    }
  }
}
object Ten {
  def main(args: Array[String]) {
    val richFile2 = RichFile2("/home/cay/readme.txt")
    val RichFile2(r @ _*) = richFile2
    println(r)
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值