1

给定一个ev: Manifest[T]我可以得到一个Class[T]using ev.erasure.asInstanceOf[Class[T]]。很遗憾,ev.erasure仅返回静态类型的Class[_].

我可以Class[T]从清单中获得一个而不进行强制转换吗?如果不是,那么有福的 Scala 创造者在方法中选择原始返回类型是有原因的erasure吗?

我知道这可能对大多数代码的影响可以忽略不计,但我在一段可以说是非惯用的 Scala 代码中遇到了这个问题,并且比其他任何事情都好奇。

4

3 回答 3

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
于 2012-06-06T19:38:31.650 回答
3

No, you have to do the cast yourself — and it should be so. This cast is potentially unsafe, depending on what you want to do with the returned Class instance. Imagine I want to roll in my own version of a cast:

def cast[T](obj: Any)(implicit m: Manifest[T]) =
  m.erasure.asInstanceOf[Class[T]].cast(obj)

This is dangerous — as indicated by the unchecked asInstanceOf. Why? Because this code runs fine with such nonsense, for instance:

val listInt = List(1, 2, 3)
val listString = cast[List[String]](listInt)

There, a List[Int] typed as a List[String]. And this compiles and runs fine, but you'll probably get a ClassCastException later in your code at an unexpected line. That's why you cannot directly get a Class[T] from a Manifest[T] — because it is unsafe.

于 2012-06-06T21:42:12.523 回答
1

Scala 的类型系统没有足够的表现力来为erasure. 正确的类型类似于getClass():

实际结果类型是Class<? extends |X|>|X| 是调用 getClass 的表达式的静态类型的擦除。

在这种情况下,我认为正确的类型应该是Class[|X|](因为Manifest[T]它的类型参数是不变的)。这与 不同Object.getClass(),因为在这种情况下静态类型和运行时类型可能不同:

Number n = 0; 
Class<? extends Number> c = n.getClass();

在这里,运行时类型cClass<Integer>,而不是Class<Number>

于 2012-06-06T21:49:38.310 回答