"No default Typeable for parametrized type" 使用 Shapeless 2.1.0-RC2

"No default Typeable for parametrized type" using Shapeless 2.1.0-RC2

我试图使用 Shapeless Typeable 使对 Java 库的访问更加类型安全,但 运行 成为障碍。我不确定我是否在滥用该库,必须手动提供一个 type-class 实例,或者是否有其他问题。

此代码演示了我的问题的简化演示..

import shapeless._
import syntax.typeable._

def gaugeOpt(name: String): Option[Gauge[Double]] = {
  return registry.getGauges.get(name).cast[Gauge[Double]]
}

..使用 Shapeless-2.1.0-RC2 和 Scala 2.11.5 导致此错误:

No default Typeable for parametrized type com.codahale.metrics.Gauge[Double]

显示的库并不重要;只是对在我的 Scala 代码中使用它们时使 Java 库更加类型安全的一般模式感兴趣。

解法:

根据已接受答案的建议,我编写了以下类型 class 实例:

implicit def gaugeTypeable[T](implicit castT: Typeable[T]): Typeable[Gauge[T]] =
  new Typeable[Gauge[T]] {
    def cast(t: Any): Option[Gauge[T]] = {
      if(t == null) None
      else if(t.isInstanceOf[Gauge[_]]) {
        castT.cast(t.asInstanceOf[Gauge[_]].getValue) match {
          case None => None
          case _ => Some(t.asInstanceOf[Gauge[T]])
        }
      } else None
    }
  }

唯一需要注意的是,我必须访问仪表值访问器才能恢复已擦除的类型。

没有参数化的类型有一个默认的 Typeable 实例,因为您可以通过检查它们的运行时间 class 来安全地(大概)转换它们。但是由于泛型在运行时被删除,这对于参数化类型来说是不安全的; t.getClass() 可能 return Gauge.class,但这并不能保证 tGauge[Double] 而不是 Gauge[Int].

您需要手动提供类型class实例:

implicit def gaugeTypeable[A](implicit innerTypeable: Typeable[A]) =
  new Typeable[Gauge[A]] {
    def cast(t: Any): Option[Gauge[A]] = ...
      //confirm whether t is really a Gauge[A]
      //probably making use of innerTypeable to check the
      //"inner" value
  }