《快学scala》习题解答-第十八章-高级类型

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

第十八章 高级类型

18.1
实现一个Bug类,对沿着水平线爬行的虫子建模。move方法向当前方向移动,turn方法让虫子转身,show方法打印出当前的位置。让这些方法可以被串接调用。例如:
bugsy.move(4).show().move(6).show().turn().move(5).show()
上述代码应显示4 10 5。

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
package _1801 {
class Bug(var pos: Int = 0) {
var forword: Int = 1
def move(up: Int):this.type = {
pos += forword * up
this
}
def show():this.type = {
print(pos + " ")
this
}
def turn():this.type = {
forword = -forword
this
}
}
class Test extends App {
val bugsy = new Bug
bugsy.move(4).show().move(6).show().turn().move(5).show()
}
}

18.2
为前一个练习中的Bug类提供一个流利接口,达到能编写如下代码的效果:
bugsy move 4 and show and then move 6 and show turn around move 5 and show

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package _1802 {
//非动词 non-verb
object then
object show
object around
class Bug(var pos: Int = 0) {
var forword: Int = 1
def move(num: Int): this.type = { pos += num; this }
def and(obj: then.type): this.type = this
def and(obj: show.type): this.type = { print(pos + " "); this}
def turn(obj: around.type): this.type = { pos = 0; this}
}
class Test extends App {
val bugsy = new Bug
bugsy move 4 and show and then move 6 and show turn around move 5 and show
}
}

18.3
完成18.1节中的流利接口,以便我们可以做出如下调用:
book set Title to “Scala for the Impatient” set Author to “Cay Horstmann”

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
class Document {
var title: String = ""
var author: String = ""
def setTitle(title: String):this.type = {this.title = title; this}
def setAuthor(author: String):this.type = {this.author= author; this}
}
//可枚举
object Title
object Author
class Book extends Document{
private var useNextArgAs:Any = null
def set(obj: Any): this.type = {useNextArgAs = obj; this}
def to(obj:String) = {
useNextArgAs match{
case Title => setTitle(obj)
case Author => setAuthor(obj)
case _ =>
}
this
}
}
object Main extends App {
val book = new Book
book set Title to "Scala for the Impatient" set Author to "Cay Horstmann"
println(book.title)
println(book.author)
}

18.4
实现18.2节中被嵌套在Network类中的Member类的equals方法。两个成员要想相等,必须属于同一个网络。

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
import scala.collection.mutable.ArrayBuffer
class Network {
class Member(val name: String) {
val contacts = new ArrayBuffer[Member]
def canEqual(other: Any): Boolean = other.isInstanceOf[Member]
override def equals(other: Any): Boolean = other match {
case that: Member =>
(that canEqual this) &&
name == that.name
case _ => false
}
}
private val members = new ArrayBuffer[Member]
def join(name: String) = {
val m = new Member(name)
members += m
m
}
}
val network1 = new Network().join("1")
val network2 = new Network().join("1")
println(network1.equals(network2))

18.5
考虑如下类型别名
type NetworkMember = n.Member forSome { val n : Network }
和函数
def process(m1: NetworkMember, m2: NetworkMember) = (m1, m2)
这与18.8节中的process函数有什么不同?

与18.8不同,允许不同网络作为参数

18.6
Scala类库中的Either类型可以被用于要么返回结果,要么返回某种失败信息的算法。编写一个带有两个参数的函数:一个已排序整数数组和一个整数值。要么返回该整数值在数组中的下标,要么返回最接近该值的元素的下标。使用一个中置类型作为返回类型。

1
2
3
4
5
6
7
8
def getIndex(arr: Seq[Int], v: Int): Int Either Int = {
if (arr.contains(v)) {
Left(arr.indexOf(v))
} else {
Right(arr.indexOf(arr.reduce((a,b) => if (math.abs(v - a) > math.abs(v - b)) b else a)))
}
}
println(getIndex(Seq(2,3,4,5,-2,-3),1))

18.7
实现一个方法,接受任何具备如下方法的类的对象和一个处理该对象的函数。
调用该函数,并在完成或有任何异常发生时调用close方法。
def close(): Unit

1
2
3
4
5
6
7
def tryWithClose[T<:{def close():Unit}](obj:T,func: T => Unit)={
try{
func(obj)
}finally {
obj.close()
}
}

18.8
编写一个函数printValues,带有三个参数f、from和to,打印出所有给定区间范围内的输入值经过f计算后的结果。这里的f应该是任何带有接受Int产出Int的apply方法的对象。例如:
printValues((x: Int) => x*x, 3, 6) //将打印 9 16 25 36
printValues(Array(1, 1, 2, 3, 5, 8, 13, 21, 34, 55), 3, 6) //将打印 3 5 8 13

1
2
3
4
5
6
7
def printValues(f:{def apply(param:Int):Int}, from:Int, to:Int)={
for(i <- from to to) {
print(f.apply(i) + " ")
}
}
printValues((x: Int) => x*x, 3, 6) //将打印 9 16 25 36
printValues(Array(1, 1, 2, 3, 5, 8, 13, 21, 34, 55), 3, 6) //将打印 3 5 8 13

18.9
考虑如下对物理度量建模的类:
abstract class DimT{
protected def create(v: Double): T
def + (other: Dim[T]) = create(value + other.value)
override def toString() = value + “ “ + name
}
以下是具体子类:
class Seconds(v: Double) extends DimSeconds{
override def create(v: Double) = new Seconds(v)
}
但现在不清楚状况的人可能会定义
class Meters(v: Double) extends DimSeconds{
override def create(v: Double) = new Seconds(v)
}
允许米(Meters)和秒(Seconds)相加。使用自身类型来防止发生这样的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
abstract class Dim[T](val value: Double, val name: String){
this: T =>
protected def create(v: Double): T
def + (other: Dim[T]) = create(value + other.value)
override def toString() = value + " " + name
}
class Seconds(v: Double) extends Dim[Seconds](v, "s"){
override def create(v: Double) = new Seconds(v)
}
class Meters(v: Double) extends Dim[Seconds](v, "m"){
override def create(v: Double) = new Seconds(v)
}
//Meters can not extends Dim[Seconds] and compile fail

18.10
自身类型通常可以被扩展自身的特质替代,但某些情况下使用自身类型会改变初始化和重写的顺序。构造出这样的一个示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
trait A {
def sing() = "from a"
}
trait C {
this: A =>
val w = sing + "from c"
}
class B{
this: C =>
val k = w
}
val b = new B with C with A
println(b.k)

参考:
《快学Scala》:http://book.douban.com/subject/19971952/

(转载本站文章请注明作者和出处 Vernon Zheng(郑雪峰) – vernonzheng.com ,请勿用于任何商业用途)