【问题标题】:Scala Co-Variant Bounded TypesScala 协变有界类型
【发布时间】:2017-05-05 00:41:50
【问题描述】:

我正在通过以下示例使用 Scala 的类型系统:

scala> sealed trait A
defined trait A

scala> case class A1(n: Int) extends A
defined class A1

scala> case class A2(n: Int) extends A
defined class A2

scala> case class MyCase[+P <: A](a: A, y: String)
defined class MyCase

scala> val l = List(MyCase[A1](A1(1), "A1"), MyCase[A2](A2(2), "A2"))

现在,当我执行以下操作时:

scala> l.head.asInstanceOf[MyCase[A2]]
res2: MyCase[A2] = MyCase(A1(1),A1)

如何将MyCase[A1] 实例分配给MyCase[A2] 引用?我的意思是 MyCase[A1]MyCase[A2] 在对象层次结构中处于同一级别!

【问题讨论】:

  • 是的,很抱歉造成混乱!我的问题实际上是一些东西。我修改了上面的帖子
  • 如果没有使用类型参数 P,那有什么意义呢?
  • “如何将MyCase[A1] 对象分配给MyCase[A2] 引用?” -- 因为你用类型强制它演员。
  • asInstanceOf 是不安全的操作。你告诉编译器“相信我,我知道我在做什么”。如果强制转换无效,您可能会立即收到运行时错误,或者您可能不会 - 您可能会在以后遇到问题。 asInstanceOf 从不在普通的 Scala 代码中使用。

标签: scala


【解决方案1】:

据我了解,您想知道为什么在运行时没有收到错误,而您却执行了l.head.asInstanceOf[MyCase[A2]]。所以答案很简单——type erasure。对于 JVM,这两种类型都是相等的,因为它忽略了泛型参数——它根本不知道它们,因为它们只存在于编译器级别,所以只有编译器可以给你一个例外:

scala> val mcA2: MyCase[A2] = l.head
<console>:15: error: type mismatch;
 found   : MyCase[Product with Serializable with A]
 required: MyCase[A2]
       val mcA2: MyCase[A2] = l.head
                                ^

但是,asInstanceOf 会忽略此检查。所以当你这样做时

case class MyCase[+P <: A](a: P) //P instead of A
scala> val k = MyCase[A1](A1(0)).asInstanceOf[MyCase[A2]]
k: MyCase[A2] = MyCase(A1(0))

scala> val a: A2 = k.a
java.lang.ClassCastException: A1 cannot be cast to A2
... 33 elided

但是在您的示例中-您从未在运行时真正使用过P(而且这是不可能的),因此您永远不会得到ClassCastException。实际上,在这些条件下(没有实际实例),您可以执行类型级别的 copy like here,但为此使用特征更安全。

【讨论】:

  • 这个练习只是为了让我了解 Scala 的有界类型。到目前为止,我对这个例子很感兴趣。为什么我会关心有界类型?我可以使用有界类型的典型用例有哪些?
  • 很简单,例如,您甚至不能创建MyCase[String],因为它与A 绑定(当然没有asInstanceOf)。协方差(A &gt;: B =&gt; M[A] &gt;: M[B])与它绝对正交,只要asInstanceOf,它就是不相关的。
猜你喜欢
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
  • 2012-04-08
  • 2015-06-03
  • 1970-01-01
  • 1970-01-01
  • 2012-08-02
  • 2020-01-25
相关资源
最近更新 更多