scala中的类型擦除和继承

kon*_*tor 3 inheritance scala type-erasure

我有以下类层次结构.

trait Item {val id: String}

case class MItem(override val id: String, val name: String) extends Item

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name)

val d = new DItem("1", "one", "another one")
println(d)
Run Code Online (Sandbox Code Playgroud)

预期产出

DItem(1, one, another one)
Run Code Online (Sandbox Code Playgroud)

实际产出

Mitem(1,one)
Run Code Online (Sandbox Code Playgroud)

为什么会这样呢?建议什么,以便我得到我的对象的真实类型和非类型的超类.

vsm*_*kov 5

这不是类型擦除.您获得此结果是因为DItem获取toString()实现继承自Mitem.你必须覆盖它才能得到你想要的东西

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
    override def toString = s"DItem($id, $name, $name2)"
}
Run Code Online (Sandbox Code Playgroud)

所以这是一个结果:

scala> val d = new DItem("1", "one", "another one")
d: DItem = DItem(1, one, another one)

scala> println(d)
DItem(1, one, another one)
Run Code Online (Sandbox Code Playgroud)

从case类继承几乎总是一个坏主意,因为除了toString继承类之外还将继承equalshashCode.

另一个缺点是对于这种后继类的有限模式匹配,即不可能在case分支中使用这样的类并且可能导致混淆错误.

case class A(id: String)
class B(id: String, name: String) extends A(id)

new B("foo", "bar") match {
  case A(id) => println(id)
  case other => println(other)
}
Run Code Online (Sandbox Code Playgroud)

您可能希望此代码中没有错误,但您会得到

<console>:17: error: constructor cannot be instantiated to expected type;
 found   : A
 required: B
     case A(id) => println(id)
          ^
Run Code Online (Sandbox Code Playgroud)

但是,如果您B明确地推断出一种类型,它将起作用

scala> new B("foo", "bar").asInstanceOf[A] match {
     |   case A(id) => println(id)
     |   case other => println(other)
     | }
foo
Run Code Online (Sandbox Code Playgroud)

所以...从案例类继承是非常容易出错和混乱的,除非你知道你在做什么,否则应该避免.

  • 我想提到[案例类继承是一个坏主意](http://stackoverflow.com/questions/11158929/what-is-so-wrong-with-case-class-inheritance)会增加答案. (2认同)