1. 定义一个不可变类Pair[T,S],带一个swap方法,返回组件交换过位置的新对偶。
package ex17_01
object Main extends App {
val p = new Pair(97 -> 'a')
val a = p.swap
println(a)
}
class Pair[T, S](val p: (T, S)) {
def swap = {
(p._2, p._1)
}
}
/*output:
(a,97)
*/
2. 定义一个可变类Pair[T],带一个swap方法,交换对偶中组件的位置。
package ex17_02
object Main extends App {
val p = new Pair(97 -> 'a')
println(p.swap)
p.p = 98 -> 'b'
println(p.swap)
}
class Pair[T](var p: (T, T)) {
def swap = {
(p._2, p._1)
}
}
/*output:
(a,97)
(b,98)
*/
3. 给定类Pair[T,S],编写一个泛型方法swap,接受对偶作为参数并返回组件交换过位置的新对偶。
package ex17_03
object Main extends App {
val p = new Pair
println( p.swap( 97 -> 'a' ) )
}
class Pair[T, S] {
def swap[T, S](p: (T, S)) = {
(p._2, p._1)
}
}
/*output:
(a,97)
*/
4. 在17.3节中,如果我们想把Pair[Person]的第一个组件替换成Student,为什么不需要给replaceFirst方法定一个下界?
回答:因为Student是Pair的子类(型),所以不需要给replaceFirst方法定一个下界即可把Pair[Person]的第一个组件替换成Student。
package ex17_04
object Main extends App {
val p1 = new Person
val p2 = new Person
val s1 = new Student
val pair = new Pair(p1, p2)
pair.replaceFirst(s1) //返回值类型为 Pair[Person]
}
class Pair[T](val first: T, val second: T) {
def replaceFirst(newFirst: T) = new Pair[T](newFirst, second)
}
class Person
class Student extends Person
/*output:
(a,97)
*/
5. 为什么RichInt实现的是 Comparable[Int]而不是Comparable[RichInt]?
回答:RichInt是Int的富包装类,提供了很多便捷方法,其目的不是为了取代Int而是增强Int。
而接口 Comparable 位于 java.lang包。实现 Comparable[Int] 比 实现 Comparable[RichInt] 通用得多。
package ex17_05
import scala.runtime.RichInt
object Main extends App {
val a = new RichInt(1)
val b = new RichInt(2)
val c = 3
//println ( a max b) //type mismatch; found : scala.runtime.RichInt required: Int
println ( a max c)
}
/*output:
3
*/
6. 编写一个泛型方法middle,返回任何Iterable[T]的中间元素。举例来说,middle["World"]应得到'r'。
package ex17_06
object Main extends App {
def middle[T](it: Iterable[T]): T = {
def list = it.toList
list(list.size / 2)
}
val str = "World"
println("%s's middle is %c".format(str, middle(str)))
}
/*output:
World's middle is r
*/
7. 查看Iterable[+A]特质。哪些方法使用了类型参数A?为什么在这些方法中类型参数位于协变点?
解答:foldLeft, foldRight, groupBy 等方法使用了类型参数A。因为在函数参数中,型变是反转过来的——它的参数是协变的。
8. 在17.10节中,replaceFirst方法带有一个类型界定。为什么你不能对可变的Pair[T]定义一个等效的方法?
def replaceFirst[R >: T](newFirst : R) { first = newFirst) //错误
回答:首先,newFirst无法赋值给first。因为first是T类型,而newFirst是R类型,而T是R的子类型而非亲类型。
其次,可变的Pair[T],会导致下述编译错误:
covariant type T occurs in contravariant position in type T of value first_=
covariant type T occurs in contravariant position in type T of value second_=
完整代码:
package ex17_08
object Main extends App {
}
//covariant type T occurs in contravariant position in type T of value first_=
//covariant type T occurs in contravariant position in type T of value second_=
//class Pair[+T](val first: T, val second: T) { //ERROR
class Pair[T](var first: T, var second: T) {
//type mismatch; found : newFirst.type (with underlying type R) required: T
//def repalceFirst[R >: T](newFirst: R) { first = newFirst } //ERROR
}
9. 在一个不可变类Pair[+T]中限制方法参数看上去可能有些奇怪。不过,先假定你可以在Pair[+T]中定义
def replaceFirst(newFirst : T)
问题在于,该方法可能会被重写(以某种不可靠的方式)。构造出这样的一个示例。
定义一个Pair[Double]的子类NastyDoublePair,重写replaceFirst方法,用newFirst的平方根开做新对偶。
然后对实际类型为 NastyDoublePair的 Pair[Any]调用 replaceFirst("Hello")。
解答:
// 假定可以不用限制方法参数,那么对实际类型为NastyDoublePair的Pair[Any]调用replace("Hello")时,
// 调用的是NastyDoublePair中重写了的replaceFirst,而其要求的是Double,所以会出错:type mismatch。
package ex17_09
object Main extends App {
}
class Pair[+T](val first: T, val second: T) {
//covariant type T occurs in contravariant position in type T of value newFirst
//def replaceFirst(newFirst: T) = {null} // ERROR
def replaceFirst[R >: T](newFirst: R) = new Pair[R](newFirst, second)
}
class NastyDoublePair[Double](override val first: Double, override val second: Double) extends Pair[Double](first, second) {
//type mismatch; found : Double(in class NastyDoublePair) required: scala.Double
//override def replaceFirst(newFirst: Double) = new Pair(math.sqrt(newFirst), second) //ERROR
}
10. 给定可变类Pair[S, T],使用类型约束定义一个swap方法,当类型参数相同时可以被调用。
回答:
package ex17_10
object Main extends App {
val a = new Pair(2, 4)
println(a)
val b = new Pair("Hi", 1)
println(b)
}
class Pair[S, T](private var first: S, private var second: T) {
def swap(implicit ev1: S =:= T, ev2: T =:= S) { // 这里需要双重的 类型约束
val temp = first
first = second
second = temp
}
override def toString() = "(" + first +", " + second + ")"
}
/*output:
(2, 4)
(Hi, 1)
*/