鉴于ev: Manifest[T]
,我可以使用Class[T]
获得ev.erasure.asInstanceOf[Class[T]]
。遗憾的是ev.erasure
单独返回静态类型Class[_]
。
我可以在没有投射的情况下从清单中获得Class[T]
吗?如果没有,为什么有幸的Scala创建者在erasure
方法中使用原始返回类型?
我知道这可能会对大多数代码产生微不足道的影响,但我在一个可以说是非惯用的Scala代码中遇到了这个问题,而且我对此感到好奇。
答案 0 :(得分:4)
返回已删除类型的原因是,Manifest
几乎总是在通用代码中使用,其中 实际上拥有该类型。这会强制您明确声明您的意图,而不是错误地假设它实际上检查该类型是您想要的类型。
您当然可以使用我的库模式来添加自己保留类型的方法:
class ClassFriendlyManifester[T](m: Manifest[T]) {
def toClass = m.erasure.asInstanceOf[Class[T]]
}
implicit def manifests_like_classes[T](m: Manifest[T]) = new ClassFriendlyManifester(m)
def example[T: Manifest] = implicitly[Manifest[T]].toClass
scala> example[String]
res2: Class[String] = class java.lang.String
def example2[T](implicit ev: Manifest[T]) = ev.toClass
scala> example2[String]
res5: Class[String] = class java.lang.String
答案 1 :(得分:3)
不,你必须自己做演员 - 而且应该如此。此转换可能不安全,具体取决于您要对返回的Class
实例执行的操作。想象一下,我想要推出自己的演员版本:
def cast[T](obj: Any)(implicit m: Manifest[T]) =
m.erasure.asInstanceOf[Class[T]].cast(obj)
这很危险 - 正如未经检查的asInstanceOf
所示。为什么?因为这段代码运行良好,例如:
val listInt = List(1, 2, 3)
val listString = cast[List[String]](listInt)
在那里,List[Int]
输入为List[String]
。这可以编译并运行正常,但是您可能会在代码中稍后在意外行中获得ClassCastException
。这就是为什么你不能直接从Class[T]
获得Manifest[T]
- 因为它不安全。
答案 2 :(得分:1)
Scala的类型系统的表达力不足以为erasure
提供正确的类型。正确的类型与getClass()
的类型相似:
实际结果类型为
Class<? extends |X|>
,其中| X |是个 擦除getClass所在表达式的静态类型 调用。
在这种情况下,我认为正确的类型是Class[|X|]
(因为Manifest[T]
在其类型参数中是不变的)。这与Object.getClass()
不同,因为在这种情况下,静态类型和运行时类型可能不同:
Number n = 0;
Class<? extends Number> c = n.getClass();
此处,c
的运行时类型为Class<Integer>
,而不是Class<Number>
。