繁体   English   中英

scala中的类型擦除和继承

[英]type erasure and Inheritance in scala

我有以下类层次结构。

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)

预期产出

DItem(1, one, another one)

实际产出

Mitem(1,one)

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

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

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)"
}

所以这是一个结果:

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

scala> println(d)
DItem(1, one, another one)

从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)
}

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

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

但是,如果您明确地推断B实例的类型,它将起作用

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

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

据我所知,不推荐使用case类继承。 所以case类可以(应该)只从常规类继承。

做println通常会在对象上调用toString传递给它。

所以你的代码会发生什么,它会调用对象的toString实现,恰好是具有这种实现的MItem。

所以你需要覆盖DItem上的toString,如下所示:

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)"
}

如果你想获得对象的类型,可以使用getClass。

println(d.getClass)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM