Void 和 intersection 类型的奇怪行为
Strange behavior of Void and intersection types
这是预期的行为吗?
scala> val l: List[Void] = "I'm void".asInstanceOf[String with Void] :: Nil
l: List[Void] = List(I'm void)
将 l
识别为 List[Void]
并将 String
显示为第一个元素是否有效?
从某种意义上说,这是完全正确的,并不特定于 Void
。 "I'm void".asInstanceOf[String with Void]
本身 不会 抛出 ClassCastException
直到您实际尝试以需要将其视为无效类型的方式使用它。
val l: List[Void] = "I'm void".asInstanceOf[String with Void] :: Nil
这是有效的,因为我们在欺骗编译器说 "I'm void"
是 String with Void
的实例,而 String with Void
是 [=13= 的子类型],这意味着我们可以 暂时 有一个 List[Void]
,因为 List[String with Void] <: List[Void]
。 但是,如果我们尝试访问List[Void]
的头部,我们期望Void
,而原来的String
不是。
scala> l.head
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Void
一开始它似乎可以工作,因为所有东西都有一个 toString
方法,所以它不需要被视为 Any
以外的任何东西。
如果我们用 String with Int
试试,也会发生同样的事情。
scala> val int = "I'm an Int".asInstanceOf[String with Int]
int: String with Int = I'm an Int
scala> int % 2
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
String with Int
将愉快地存在,直到现实出现,我们意识到它实际上不是 Int
,并且没有 %
方法。
对@m-z 解释为什么 .asInstanceOf[String with Void]
不抛出的答案的轻微扩展。我们需要区分什么存在于 Scala 中,什么存在于 JVM 字节码中。特别是,字节码不支持像 String with Void
这样的交集类型,因此不能转换为它。因此 .asInstanceOf[String with Void]
发出的字节码实际上与 .asInstanceOf[String]
相同;但是当编译器看到这种类型的值用作 Void
时,它会插入额外的转换。
这与使用 isInstanceOf
无法区分具有不同参数(如 List[Int]
和 List[String]
)的泛型类型的原因相同:就字节码而言,类型相同。
这是预期的行为吗?
scala> val l: List[Void] = "I'm void".asInstanceOf[String with Void] :: Nil
l: List[Void] = List(I'm void)
将 l
识别为 List[Void]
并将 String
显示为第一个元素是否有效?
从某种意义上说,这是完全正确的,并不特定于 Void
。 "I'm void".asInstanceOf[String with Void]
本身 不会 抛出 ClassCastException
直到您实际尝试以需要将其视为无效类型的方式使用它。
val l: List[Void] = "I'm void".asInstanceOf[String with Void] :: Nil
这是有效的,因为我们在欺骗编译器说 "I'm void"
是 String with Void
的实例,而 String with Void
是 [=13= 的子类型],这意味着我们可以 暂时 有一个 List[Void]
,因为 List[String with Void] <: List[Void]
。 但是,如果我们尝试访问List[Void]
的头部,我们期望Void
,而原来的String
不是。
scala> l.head
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Void
一开始它似乎可以工作,因为所有东西都有一个 toString
方法,所以它不需要被视为 Any
以外的任何东西。
如果我们用 String with Int
试试,也会发生同样的事情。
scala> val int = "I'm an Int".asInstanceOf[String with Int]
int: String with Int = I'm an Int
scala> int % 2
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
String with Int
将愉快地存在,直到现实出现,我们意识到它实际上不是 Int
,并且没有 %
方法。
对@m-z 解释为什么 .asInstanceOf[String with Void]
不抛出的答案的轻微扩展。我们需要区分什么存在于 Scala 中,什么存在于 JVM 字节码中。特别是,字节码不支持像 String with Void
这样的交集类型,因此不能转换为它。因此 .asInstanceOf[String with Void]
发出的字节码实际上与 .asInstanceOf[String]
相同;但是当编译器看到这种类型的值用作 Void
时,它会插入额外的转换。
这与使用 isInstanceOf
无法区分具有不同参数(如 List[Int]
和 List[String]
)的泛型类型的原因相同:就字节码而言,类型相同。