Scala練習(十一)
\1. 根據優先順序規則, 3 + 4 -> 5 和 3 -> 4 + 5 是如何被求值的?
1 |
在REPL中執行即可得到結果。都是從左至右執行 |
\2. BigInt 類有一個pow方法,但沒有用操作符字元,Scala類庫的設計者為什麼沒有選用**(像Fortran那樣)或者^(像Pascal那樣)作為乘方操作符呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Scala中的操作符就是方法,其優先順序是根據首字母來判斷的,優先順序如下
最高優先順序:除以下字元外的操作符字元
* / %
+ -
:
= !
< >
&
ˆ
|
非操作符
最低優先順序:賦值操作符
一般乘方的操作符是優於乘法操作的,如果使用**作為乘方的話,那麼其優先順序則與*相同,而如果使用^的話,則優先順序低於*操作。優先順序都是有問題的。故沒有使用這兩種操作符
|
\3. 實現Fraction類,支援 + - * / 操作,支援約分, 例如將 15 / -6 變成 -5 / 2。除以最大公約數,像這樣:
1 2 3 4 5 6 7 8 9 10 |
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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
class Fraction(n : Int, d: Int) { private val num : Int = if (d == 0) 1 else |
\4. 實現一個Money類,加入美元和美分欄位。提供 +、-操作符已經比較操作符==和\< 。舉例來說,Money(1, 75) + Money(0, 50) == Money(2, 25) 應為true, 你應該同時提供 * 和 / 操作符嗎?為什麼?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
class Money(private val d: Int, private val c: Int) { private var dollars = d; private val cents = { if (c >= 100) { dollars += c / 100 c % 100 } else if (c < -100) { dollars -= c / 100 c % 100 } else { c } } override def toString = { "(" + dollars + "," + cents + ")" } def +(a: Money) = { new Money(this.dollars + a.dollars, this.cents + a.cents); } def -(a: Money) = { new Money(this.dollars - a.dollars, this.cents - a.cents); } def ==(a: Money) = { (this.dollars * 100 + this.cents) == (a.dollars * 100 + a.cents) } def <(a: Money) = { (this.dollars * 100 + this.cents) < (a.dollars * 100 + a.cents) } } object Money { def apply(d: Int, c: Int) = new Money(d, c); def unapply(o: Money) = { Some((o.dollars, o.cents)) } } object MoneyTest extends App { val c = Money(2, 175); val Money(a: Int, b: Int) = c println(a) println(Money(1, 75) + Money(0, 50) == Money(2, 25)) } |
對於美元操作乘、除是沒有意義.
\5. 提供操作符用於構造HTML表格。例如:
1 |
Table() | "Java" | "Scala" || "Gosling" | "Odersky" || "JVM" | "JVM, .NET" |
應產出:
1 |
<table><tr><td>Java</td><td>Scala</td></tr><tr><td>Gosling</td><td>Odersky</td></tr><tr><td>JVM</td><td>JVM, .NET</td></tr></table> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import scala.collection.mutable.ArrayBuffer class Table { private val trTags : ArrayBuffer[String] = ArrayBuffer(); private val tdTags : ArrayBuffer[String] = ArrayBuffer(); def |(str: String) = { tdTags += str this } def ||(str: String) : Table= { trTags += "<tr><td>" + tdTags.mkString("</td><td>") + "</td><tr>" tdTags.clear() tdTags += str this } override def toString = { if (!tdTags.isEmpty) { trTags += "<tr><td>" + tdTags.mkString("</td><td>") + "</td><tr>" } "<table>" + trTags.mkString("")+ "</table>" } } object Table { def apply() = new Table() } object TableTest extends App { val str = Table() | "Java" | "Scala" || "Gosling" | "Odersky" || "JVM" | "JVM, .NET" println(str) } |
\6. 提供一個ASCIIArt 類,其物件包含類似這樣的圖形:
1 2 3 4 5 |
/\_/\ ( ' ' ) ( _ ) | | | (__|__) |
提供將兩個ASCIIArt圖形橫向或縱向結合的操作符,選用適當優先順序的操作符命名。橫向結合的例項:
1 2 3 4 5 |
/\_/\ ----- ( ' ' ) / Hello \ ( _ )< Scala | | | | \ Coder / (__|__) ----- |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import scala.collection.mutable.ArrayBuffer class ASCIIArt(str: String) { val artMap : ArrayBuffer[String] = new ArrayBuffer[String]() if (str != null && !str.trim.eq("")) { str.split("[\r\n]+").foreach((line: String) => { val tmp = new ArrayBuffer[String](); artMap += line }) } def this() { this("") } def +(other: ASCIIArt) : ASCIIArt = { val art = new ASCIIArt() val length = if (this.artMap.length >= other.artMap.length) this.artMap.length else other.artMap.length for (i <- 0 until length) { val thisCur : String = if (this.artMap.isDefinedAt(i)) this.artMap(i) else "" val otherCur : String = if (this.artMap.isDefinedAt(i)) other.artMap(i) else "" art.artMap += thisCur + otherCur } art } def *(other: ASCIIArt) : ASCIIArt = { val art = new ASCIIArt() art.artMap ++= this.artMap art.artMap ++= other.artMap art } override def toString = { artMap.mkString("\n") } } object ASCIIArt { def apply(str: String) = new ASCIIArt(str) } object ASCIIArtTest extends App { val a1 = ASCIIArt(""" /\_/\ |( ' ' ) |( - ) | | | | |(__|__) |""".stripMargin) val a2 = ASCIIArt(""" ----- | / Hello \ | < Scala | | \ Coder / | ----- |""".stripMargin) println(a1 + a2) println(a1 * a2) } |
\7. 實現一個BigSequence 類,將64個bit的序列包在一個Long值中。提供apply和update操作來獲取和設定某個位置具體的bit
1 |
// todo
|
\8. 提供一個Matrix類—-你可以選擇需要的是一個2x2的矩陣,任意大小的正方形矩陣,或是mxn的矩陣。支援+和*操作。*操作應同樣適用於單值,例如 mat * 2. 單個元素可以通過 mat(row,col)得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
import scala.collection.mutable.ArrayBuffer class Matrix(private val data: Array[Int], private val nrow: Int){ private val matrixData : Array[Array[Int]] = { val cols = (data.length.toFloat / nrow).ceil.toInt val result : Array[Array[Int]] = Array.ofDim[Int](nrow, cols); for (i <- 0 until nrow) { for (j <- 0 until cols) { val index = i*cols + j result(i)(j) = if (data.isDefinedAt(index)) data(index) else 0 } } result } override def toString = { var str = "" matrixData.map((p: Array[Int]) => { p.mkString(",") }).mkString("\n") } def *(a: Matrix) = { val data: ArrayBuffer[Int] = ArrayBuffer(); for (i <- 0 to a.matrixData.length - 1) { for (j <- 0 to a.matrixData(0).length - 1) { data += a.matrixData(i)(j) * this.matrixData(i)(j) } } new Matrix(data.toArray, a.matrixData.length) } def *(a: Int) = { val data: ArrayBuffer[Int] = ArrayBuffer(); for (i <- 0 to this.matrixData.length - 1) { for (j <- 0 to this.matrixData(0).length - 1) { data += this.matrixData(i)(j) * a } } new Matrix(data.toArray, this.matrixData.length) } def +(a: Matrix) = { val data: ArrayBuffer[Int] = ArrayBuffer(); for (i <- 0 to this.matrixData.length - 1) { for (j <- 0 to this.matrixData(0).length - 1) { data += this.matrixData(i)(j) + a.matrixData(i)(j) } } new Matrix(data.toArray, this.matrixData.length) } def mat(row: Int, col: Int) = { matrixData(row - 1)(col - 1) } } object MatrixTest extends App { val m = new Matrix(Array(1,2,3,4), 3) val n = new Matrix(Array(1,2,3,4), 3) println(m * n) println(m + n) println(m.mat(2, 2)) println(n * 10) } |
\9. 為RichFile 類定義unapply操作,提取檔案路勁、名稱和副檔名。舉例來說,檔案/home/cay/readme.txt的路勁為/home/cay, 名稱為 readme, 副檔名txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.io.File object RichFile { def unapply(filePath : String) = { val file = new File(filePath) val ext = file.getName.split("\\.") Some((file.getParent, file.getName, ext(1))) } } object RichFileTest extends App { val RichFile(path, fileName, ext) = "/home/cay/readme.txt" println(path) println(fileName) println(ext) } |
\10. 為RichFile 類定義一個unapplySeq, 提取所有路階段。舉例來說,對於/home/cay/readme.txt,你應該產出三個路勁的序列: home,cay,readme.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
object RichFile { def unapplySeq(filePath : String) : Option[Seq[String]]= { Some(filePath.trim.split("\\/")) } } object RichFileTest extends App { val str = "/home/cay/readme.txt" str match { case RichFile(str0, str1, str2, str3) => { println(str1); println(str2); } case _ => {println(str)} } } |