快學Scala習題解答—第十一章 操作符
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) } }
快學Scala習題解答—第十一章 操作符