1. 实现一个Bug类,对沿着水平线爬行的虫子建模。move方法向当前方向移动,turn方法让虫子转身,show方法打印出当前的位置。让这些方法可以被串接调用。例如:
bugsy.move(4).show().move(6).show().turn().move(5).show()
上述代码应显示 4 10 5。
package ex18_01
class Bug {
var x = 0
var y = 0
var curr_direction = 0
def move(len: Int) = {
curr_direction match {
case 0 => x += len
case 1 => y += len
case 2 => x -= len
case 3 => y -= len
}
this
}
def turn() = {
curr_direction = (curr_direction + 1) % 4
this
}
def show() = {
curr_direction match {
case 0 => print(x + " ")
case 1 => print(y + " ")
case 2 => print(x + " ")
case 3 => print(y + " ")
}
this
}
}
object Main extends App {
val bugsy = new Bug
bugsy.move(4).show().move(6).show().turn().move(5).show()
}
/*output:
4 10 5
*/
2. 为前一个练习中的Bug类提供一个流利接口,达到能编写如下代码的效果:
bugsy move 4 and show and then move 6 and show turn around move 5 and show
解答://TODO
3. 完成18.1节中的流利接口,以便我们可以做出如下调用:
book set Title to "Scala for the Impatient" set Author to "Cay Horstmann"
package ex18_03
object Main extends App {
val book = new Document
book set Title to "Scala for the Impatient" set Author to "Cay Horstmann"
println(book)
}
// 知识点: 单例类型
object Title // This object is used as an argument for a fluent interface
object Author
class Document {
private var title = ""
private var author = ""
private var useNextArgAs: Any = null
def set(obj: Title.type): this.type = { useNextArgAs = obj; this }
def set(obj: Author.type): this.type = { useNextArgAs = obj; this }
def to(arg: String): this.type = {
if (useNextArgAs == Title) title = arg
if (useNextArgAs == Author) author = arg
this
}
override def toString = getClass.getName + "[title=" + title + ", author=" + author + "]"
}
/*output:
eg18_01_b.Document[title=Scala for the Impatient]
*/
4. 实现18.2节中被嵌套在Network类中的Member类的equals方法。两个成员要想相等,必须属于同一个网络。
解答://TODO
5. 考虑如下类型别名
type NetworkMember = n.Member forSome { val n: Network }
和函数
def process(m1: NetworkMember, m2: NetworkMember) = (m1, m2)
这与18.8节中的process函数有什么不同?
解答:该函数接受相同或不同网络的成员,而18.8节中的process函数则拒绝那些来自不同网络的成员。
package ex18_05
// 知识点: 存在类型
import javax.swing._
import scala.collection.mutable._
object Main extends App {
type NetworkMember = n.Member forSome { val n: Network }
def process(m1: NetworkMember, m2: NetworkMember) = (m1, m2)
val chatter = new Network
val myFace = new Network
val fred = chatter.join("Fred")
val wilma = chatter.join("Wilma")
val barney = myFace.join("Barney")
process(fred, wilma) // OK 接受相同网络的成员
process(fred, barney) // OK 接受不同网络的成员
fred.contacts += wilma // OK
//fred.contacts += barney //ERROR
}
class Network {
class Member(val name: String) {
val contacts = new ArrayBuffer[Member]
override def toString = getClass.getName + "[name=" + name +
",contacts=" + contacts.map(_.name).mkString("[", ",", "]") + "]"
}
private val members = new ArrayBuffer[Member]
def join(name: String): Member = {
val m = new Member(name)
members += m
m
}
override def toString = getClass.getName + "[members=" + members + "]"
}
/*output:
*/
6. Scala 类库中的Either类型可以被用于要么返回结果,要么返回某种失败信息的算法。
编写一个带有两个参数的函数:一个已排序整型数组和一个整数值。要么返回该整数值在数组中的下标,要么返回最接近该值的元素的下标。
使用一个中置类型作为返回类型。
package ex18_06
// 知识点: 中置类型
import scala.util.control.Breaks._
object Main extends App {
def either(arr: Array[Int], value: Int) = {
var re: (Int, Int) = (0, 0)
if (value < arr(0)) re = arr(0) -> 0
else if (value > arr(arr.length - 1)) re = arr(arr.length - 1) -> (arr.length - 1)
else {
breakable {
for (i <- 0 until arr.length) {
if (arr(i) == value) { re = value -> i; break }
else if (i < arr.length - 1 && arr(i) < value && value < arr(i + 1)) {
if (value - arr(i) <= arr(i + 1) - value) { re = arr(i) -> i; break }
else { re = arr(i + 1) -> (i + 1); break }
}
}
}
}
re
}
val a = Array(1, 5, 6, 9)
println(either(a, 1))
println(either(a, 5))
println(either(a, 6))
println(either(a, 9))
println(either(a, 0))
println(either(a, 7))
println(either(a, 8))
println(either(a, 10))
}
/*output:
(1,0)
(5,1)
(6,2)
(9,3)
(1,0)
(6,2)
(9,3)
(9,3)
*/
7. 实现一个方法,接受任何具备如下方法的类的对象和一个处理该对象的函数。
调用该函数,并在完成或有任何异常发生时调用close方法。
package ex18_07
// 知识点: 结构类型
import scala.util.control.Breaks._
object Main extends App {
def test(obj: { def close(): Unit }, f: { def close(): Unit } => Unit) = {
try {
f(obj)
} catch {
case ex: Exception => obj.close(); ex.printStackTrace()
} finally {
obj.close()
}
}
}
8.
9.
10.