Нет Typeable по умолчанию для параметризованного типа с использованием Shapeless 2.1.0-RC2

Я пытался использовать Shapeless Typeable, чтобы сделать доступ к библиотекам Java немного более типобезопасным, но столкнулся с препятствием. Я не уверен, что я неправильно использую библиотеку, должен вручную предоставить экземпляр класса типов или что-то еще идет не так.

Упрощенная демонстрация моей проблемы демонстрируется этим кодом.

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]

Показанная библиотека не очень важна; просто интересует общая схема создания библиотек Java более безопасных типов, когда я использую их из своего кода Scala.

Решение:

Используя совет из принятого ответа, я написал следующий экземпляр класса типов:

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
    }
  }

Единственное предостережение в том, что мне нужно было получить доступ к средству доступа к калибровочному значению, чтобы восстановить стертый тип.


person Rich Henry    schedule 03.02.2015    source источник


Ответы (1)


Существует экземпляр Typeable по умолчанию для непараметризованных типов, потому что вы можете безопасно (или) приводить их, просто проверяя их класс среды выполнения. Но поскольку дженерики стираются во время выполнения, это было бы небезопасно для параметризованных типов; t.getClass() может вернуть Gauge.class, но это не гарантирует, что t будет Gauge[Double], а не, скажем, Gauge[Int].

Вам нужно вручную предоставить экземпляр класса типов:

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
  }
person lmm    schedule 03.02.2015
comment
Спасибо, я подумал, что это может быть проблемой, но я решил, что сначала проверю. В качестве руководства я рассмотрю реализацию класса типов для List. - person Rich Henry; 03.02.2015