简体   繁体   English

scala中的类型擦除和继承

[英]type erasure and Inheritance in scala

i have following class hierarchy. 我有以下类层次结构。

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)

Expected Output 预期产出

DItem(1, one, another one)

Actual Output 实际产出

Mitem(1,one)

Why is this happening. 为什么会这样呢? What is recommended so that i get the real type of my object and the not type of super class. 建议什么,以便我得到我的对象的真实类型和非类型的超类。

This is not a type erasure. 这不是类型擦除。 You are getting this result because DItem gets toString() implementation inherited from Mitem . 你得到这个结果是因为DItem得到了继承自Mitem toString()实现。 You have to override it to get what you want 你必须覆盖它才能得到你想要的东西

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

So here is a result: 所以这是一个结果:

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

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

It is almost always a bad idea to inherit from case classes because besides toString successor class will also inherit equals and hashCode . 从case类继承几乎总是一个坏主意,因为除了toString后继类还将继承equalshashCode

Another drawback is limited pattern-matching for such successor classes ie it is impossible to use such classes in case branches and may lead to confusing errors. 另一个缺点是对于这样的后继类有限的模式匹配,即在分支的case不可能使用这样的类并且可能导致混淆的错误。

Example

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

You may expect that there is no error in this code, but you'll get 您可能希望此代码中没有错误,但您会得到

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

However if you'll infer a type for B instance explicitly it will work 但是,如果您明确地推断B实例的类型,它将起作用

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

So... Inheriting from case classes is very error-prone and confusing and should be avoided unless you know what are you doing. 所以...从案例类继承是非常容易出错和混乱的,除非你知道你在做什么,否则应该避免。

Inheriting from case classes is deprecated as far as I know. 据我所知,不推荐使用case类继承。 So case classes can (should) only inherit from regular classes. 所以case类可以(应该)只从常规类继承。

doing println usually invoke toString on the object pass on it. 做println通常会在对象上调用toString传递给它。

so what happen on your code is, it will invoke the toString implementation of the object, it happens to be MItem that has this implementation. 所以你的代码会发生什么,它会调用对象的toString实现,恰好是具有这种实现的MItem。

so you need to override the toString on DItem like this: 所以你需要覆盖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)"
}

if you want to just get the type of the object you can use getClass. 如果你想获得对象的类型,可以使用getClass。

println(d.getClass)

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

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