【问题标题】:Issue with casting铸造问题
【发布时间】:2021-01-16 12:26:51
【问题描述】:
    import scala.annotation.unchecked.uncheckedVariance
    import scala.collection.immutable.Queue
    import scala.collection.mutable.ListBuffer


  abstract class Exp[+T:Manifest] { // constants/symbols (atomic)
    def tp: Manifest[T @uncheckedVariance] = manifest[T] //invariant position! but hey...
  }
  case class Sym[+T:Manifest](val id: Int) extends Exp[T] {
  }
  abstract class Def[+T] { // operations (composite)
    override final lazy val hashCode = scala.runtime.ScalaRunTime._hashCode(this.asInstanceOf[Product])
  }
  abstract class Stm
  case class TP[+T](sym: Sym[T], rhs: Def[T]) extends Stm

  abstract class Trial{
  }

  class M1() extends Trial{}
  class M2() extends Trial{}

  class N1() extends Def[M1]{}
  class N2() extends Def[M2]{}

  TP(Sym[M1]{4},new N1())

这会产生以下错误:

scala> TP(Sym[M1]{4},new N1()) java.lang.ClassCastException: 类 N1 不能转换为 scala.Product 类(N1 在未命名的模块中 加载程序 scala.tools.nsc.interpreter.IMain$TranslatingClassLoader @2098d37d; scala.Product 位于加载程序“bootstrap”的未命名模块中)
在 Def.hashCode$lzycompute(:13) 在 Def.hashCode(:13) 在 java.base/java.lang.Object.toString(Object.java:246) 在 java.base/java.lang.String.valueOf(String.java:2951) 在 java.base/java.lang.StringBuilder.append(StringBuilder.java:168) 在 scala.collection.IterableOnceOps.addString(IterableOnce.scala:1194)
在 scala.collection.IterableOnceOps.addString$(IterableOnce.scala:1186)
在 scala.collection.AbstractIterator.addString(Iterator.scala:1279)
在 scala.collection.IterableOnceOps.mkString(IterableOnce.scala:1136) 在 scala.collection.IterableOnceOps.mkString$(IterableOnce.scala:1134) 在 scala.collection.AbstractIterator.mkString(Iterator.scala:1279)
在 scala.runtime.ScalaRunTime$._toString(ScalaRunTime.scala:159) 在 TP.toString(:18) 在 scala.runtime.ScalaRunTime$.inner$1(ScalaRunTime.scala:261) 在 scala.runtime.ScalaRunTime$.stringOf(ScalaRunTime.scala:266) 在 scala.runtime.ScalaRunTime$.replStringOf(ScalaRunTime.scala:27​​4) 在 .lzycompute(:8) ... 28 省略

我期待一个 TP[Trial] 类型的对象,发生了什么?因为 Sym 和 Def 是协变类型。我错过了什么吗?

谢谢

【问题讨论】:

  • 这与N1N2 不能被this.asInstanceOf[Product] 转换成Product 有什么关系?把N1N2改成case class-es,然后就可以无异常运行了。这一切看起来相当复杂,比相关实体的名称所暗示的要复杂得多。您介意简要描述一下您要完成的工作吗?
  • @AndreyTyukin,我真的不明白为什么 N1 和 N2 必须是案例类,你能解释一下吗?
  • Product 上的文档基本上列出了该特征的所有常见实现——本质上是元组和案例类。由于N1 显然不是一个元组,如果它不应该导致任何ClassCastExceptions,它可能应该是一个case class。你对 Product 类型转换有什么期望?

标签: scala types casting subclass covariant


【解决方案1】:

在 Scastie,它不能重现为 https://scastie.scala-lang.org/tCD4HahgTqO4WTnlGcfWqQ,但可以重现为 https://scastie.scala-lang.org/L46PWLF2S5i4d1IGoT6UuQ

只有当我为Def#hashCode 删除lazy 时,我才能在本地复制ClassCastException

协方差无关紧要。

this.asInstanceOf[Product] 中,您尝试将Defthis 转换为Product。当您创建new N1() 时,它是当前Defthis

new N1() 作为类N1 的值不能转换为Product,因为N1 没有扩展Product

在 Scala 中,默认情况下类不扩展 Product,案例类可以。

要修复 ClassCastException,只需将 N1 设为案例类即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    相关资源
    最近更新 更多