快學Scala 第17章 - 類型參數 習題解答

1. 定義一個不可變類Pair[T,S],帶一個swap方法,返回組件交換過位置的新對偶。java

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方法,交換對偶中組件的位置。ide

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方法定一個下界?ui

回答:由於Student是Pair的子類(型),因此不須要給replaceFirst方法定一個下界便可把Pair[Person]的第一個組件替換成Student。spa

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]?scala

回答:RichInt是Int的富包裝類,提供了不少便捷方法,其目的不是爲了取代Int而是加強Int。code

而接口 Comparable 位於 java.lang包。實現  Comparable[Int] 比 實現 Comparable[RichInt] 通用得多。orm

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?爲何在這些方法中類型參數位於協變點?ci

解答: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)
 */
相關文章
相關標籤/搜索