《快学Scala》(英文版:《Scala for the Impatient》),代码已传github:
https://github.com/vernonzheng/scala-for-the-Impatient
书为第一版。scala为2.11.4,jdk1.7.45,操作系统Mac OS X Yosemite 10.10.1。
第十一章 操作符
11.1 根据优先级规则,3 + 4 -> 5和3 -> 4 + 5是如何被求值的?
1
2
3
4
5
6
7
8
9
scala> 3 +4 ->5
res0: (Int, Int) = (7 ,5 )
scala> 3 ->4 +5
<console>:8 : error: type mismatch;
found : Int(5 )
required: String
3 ->4 +5
^
11.2 BigInt类有一个pow方法,但没有用操作符字符。Scala类库的设计者为什么没有选用**(像Fortran那样)或者^(像Pascal那样)作为乘方操作符呢?
Scala中的操作符就是方法,其优先级是根据首字母来判断的,优先级如下 最高优先级:除以下字符外的操作符字符
1
2
3
4
5
6
7
8
9
10
* / %
+ -
:
= !
< >
&
ˆ
|
非操作符
最低优先级:赋值操作符
一般乘方的操作符是优于乘法操作的,如果使用*作为乘方的话,那么其优先级则与 相同,而如果使用^的话,则优先级低于*操作。优先级都是有问题的。故没有使用这两种操作符
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) … }
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
mport 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={
newFraction((this .num * other.den) + (other.num * this .den),this .den * other.den)
}
def -(other:Fraction):Fraction={
newFraction((this .num * other.den) - (other.num * this .den),this .den * other.den)
}
def *(other:Fraction):Fraction={
newFraction(this .num * other.num,this .den * other.den)
}
def /(other:Fraction):Fraction={
newFraction(this .num * other.den,this .den * other.num)
}
private def newFraction(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。你应该同时提供*和/操作符吗?为什么?
不需要提供,金额的乘除没有实际意义。
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
class Money (dollar:Int,cent:Int) {
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)
}
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
private def toCent()={
this .dollar * 100 + this .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”应产出:
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
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 / (| ) ——-
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
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class BitSequence (private var value: Long = 0) {
implicit def bool2int(b: Boolean) = if (b) 1 else 0
def update(bit: Int, state: Int) = value |= (state & 1 L) << bit % 64
def apply(bit: Int): Int = if ((value & 1 L << bit % 64 ) > 0 ) 1 else 0
override def toString = "%64s" .format(value.toBinaryString).replace(" " , "0" )
}
val x = new BitSequence()
x(5 ) = 1
x(63 ) = 1
x(64 ) = 1
println(x(5 ))
println(x)
11.8 提供一个Matrix类—你可以选择需要的是一个22的矩阵,任意大小的正方形矩阵,或m n的矩阵。支持+和操作。 操作应同样适用于单值,例如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
class Matrix (val m: Int, val n: Int=m) {
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) = {
require (n == other.n)
require (m == other.m)
var res = new Matrix(m, n)
for (i <- 0 until m; j <- 0 until n) {
res(i, j) = this .value(i)(j) + other.value(i)(j)
}
res
}
def -(other: Matrix) = this + other * -1
def *(factor: Double) = {
var res = new Matrix(m, n)
for (i <- 0 until m; j <- 0 until n) {
res(i, j) = this .value(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)
var res = new Matrix(m, n)
for (i <- 0 until m; j <- 0 until n) {
res(i, j) = prod(other, i, j)
}
res
}
override def toString = value.map(_.mkString(" " )).mkString("\n" )
}
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 ))
11.9 为RichFile类定义unapply操作,提取文件路径,名称和扩展名。举例来说,文件/home/cay/readme.txt的路径为/home/cay,名称为readme,扩展名为txt
1
2
3
4
5
6
7
8
9
10
class RichFile (val path:String) extends java .io .File (path) {
}
object RichFile {
def unapply(richFile:RichFile): Unit ={
val path = richFile.path
val pos = path.lastIndexOf("/" )
if (pos == -1 ) None else Some((path.substring(0 , pos), path.substring(pos + 1 )))
}
}
11.10 为RichFile类定义一个unapplySeq,提取所有路径段。举例来说,对于/home/cay/readme.txt,你应该产出三个路径段的序列:home,cay和readme.txt
1
2
3
4
5
object RichFile {
def unapplySeq(s: String): Option[Seq[String]] = {
if (s.trim == "" ) None else Some(s.trim.split("/" ))
}
}
参考: 《快学Scala》:http://book.douban.com/subject/19971952/
(转载本站文章请注明作者和出处 Vernon Zheng(郑雪峰) – vernonzheng.com ,请勿用于任何商业用途)