2017-12-03 101 views
4

看起來,如果案例類延伸Iterable[T],則toString方法發生更改。案例類toString與Iterable特徵糾纏?

case class MyPoint(x: Int, y: Int) 

case class MyOtherPoint(x: Int, y: Int) extends Iterable[Double] { 
    def iterator: Iterator[Double] = Iterator.fill(4)(1.0) 
} 

object Main extends App { 
    val my_pt = MyPoint(4,5) 
    println(my_pt) // MyPoint(4,5) 
    // println(my_pt.iterator) // ERROR, iterator is not a member of MyPoint 
    val my_other_pt = MyOtherPoint(4, 5) 
    println(my_other_pt) // MyOtherPoint(1.0, 1.0, 1.0, 1.0) 
    println(my_other_pt.productIterator.toList) // List(4, 5) 
} 

這似乎是相當不幸的,特別是考慮到雖然case類默認擴展Product,從而有productIterator,他們不是想延長Iterable

這是Scala編譯器中的錯誤嗎?

回答

2

這是Scala編譯器中的錯誤嗎?

不,這是(section §5.3.2,重點煤礦)在規範中定義的行爲:

每個案例類隱式覆蓋類的一些方法定義 scala.AnyRef除非同一方法的定義是已經在案例類本身給出了 ,或者在與AnyRef不同的案例類的某些基類中給出了相同方法 的具體定義。 特別是:

  • 方法toString:String返回包含 的類和它的元素的名稱的字符串表示。

你看到的是Iterable繼承TraversableLike,它具有以下toString重寫結果:

override def toString = mkString(stringPrefix + "(", ", ", ")") 

而且,如果你Xprint:jvm下編譯,你可以看到MyOtherPoint繼承了許多方法,包括被覆蓋toString

case class MyOtherPoint extends Object with Iterable with Product with Serializable { 
    // removed all other methods for brevity 
    override def toString(): String = MyOtherPoint.super.toString(); 
} 
0

您可以使用以下方法重新定義toString方法:

case class MyOtherPoint(x: Int, y: Int) extends Iterable[Double] { 
    def iterator: Iterator[Double] = Iterator.fill(4)(1.0) 
    override def toString(): String = 
    productIterator.mkString(productPrefix + "(", ",", ")") 
}