【问题标题】:Creating a Class[T] from a Manifest[T] without casting从 Manifest[T] 创建 Class[T] 而不进行强制转换
【发布时间】:2012-06-06 19:25:17
【问题描述】:

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

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

我知道这可能对大多数代码的影响可以忽略不计,但我在一段可以说是非惯用的 Scala 代码中遇到了这个问题,我对此感到好奇。

【问题讨论】:

  • 你的意思可能是ev.erasure.asInstanceOf[Class[T]],不是吗?

标签: scala type-erasure raw-types


【解决方案1】:

返回已擦除类型的原因是,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

【讨论】:

    【解决方案2】:

    不,你必须自己做演员——而且应该这样做。此强制转换可能不安全,具体取决于您要对返回的 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。这就是为什么你不能直接从 Manifest[T] 获得 Class[T] 的原因——因为它不安全。

    【讨论】:

      【解决方案3】:

      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&lt;Integer&gt;,而不是 Class&lt;Number&gt;

      【讨论】:

      • 那么问题的核心是scala类型系统不能表达擦除,Class&lt;? extends X&gt;不够好?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多