Общие рекомендации
TypeTag
с генерируются во время компиляции (которые могут иметь значительные накладные расходы времени компиляции из-за расширения макроса на каждом сайте использования) и используются во время выполнения, также генерируя некоторые потенциальные накладные расходы времени выполнения, в зависимости от точного характера их использования , Так что даже в Scala 2 их, вероятно, следует использовать только в крайнем случае (и мы надеемся решить все такие проблемы здесь, чтобы последнее средство не было необходимым). Для сравнения, вещи, которые используют instanceOf
, прямо или косвенно, чрезвычайно быстры.
Использовать отражение Java
instanceOf
- это супер быстрый . classOf
(то есть Java getClass
) почти такой же быстрый.
Использовать ClassTag
Ссылочное равенство на ClassTag
s также должно быть очень быстрым.
Использование обернутого типа в качестве экземпляра класса типа
Когда это возможно, вы можете рассмотреть возможность обертывания вашего типа в классе, чтобы придать ему конкретный тип «Java». Несмотря на то, что часто возникают накладные расходы, вы можете использовать значения классов .
Классы типов в обернутом классе часто являются хорошим способом раскрытия функциональности. Кроме того, как указал @Blaisorblade, «типовые теги - это просто класс беззаконных типов (с методами typeName: String
и tpe: Type
) + материализация экземпляра». Что приводит нас к следующему варианту:
При необходимости использует макросы
(в настоящее время не поддерживается в Dotty, но планируется)
Хотя, возможно, немного сложнее привыкнуть, конечный результат должен быть более чистым синтаксисом в коде, использующем макрос, чем если бы вы использовали TypeTag
. Кроме того, макросы используются намного дальше TypeTag
.
Избранные примеры
Соответствует параметру типа коллекции
* * Пример 1 042
Типичный вариант использования для TypeTag
, взятый из популярного поста Scala: Что такое TypeTag и как его использовать? для выполнения специального полиморфизма для типа коллекции:
import scala.reflect.runtime.universe._
def meth[A : TypeTag](xs: List[A]) = typeOf[A] match {
case t if t =:= typeOf[String] => "list of strings"
case t if t <:< typeOf[Foo] => "list of foos"
}
scala> meth(List("string"))
res67: String = list of strings
scala> meth(List(new Bar))
res68: String = list of foos
В отличие от ClassTag
, TypeTag
является отражением во время выполнения. Может быть, я использую это неправильно здесь, хотя поведение довольно удивительно. По крайней мере, в REPL я не получаю никаких предупреждений со следующим:
def meth[A : ClassTag](xs: List[A]) = xs match {
case xs: List[String] => "list of strings"
case xs: List[Foo] => "list of foos"
}
meth(List(new Bar))
res10: String = "list of strings"
Решение
Это от @smarter на gitter (предполагается, что нам не нужно обрабатывать пустые списки разных типов отдельно):
def meth[A](xs: List[A]) = xs match {
case Nil => "nil"
case (_: String) :: _ => "list of strings"
case (_: Foo) :: _ => 'list of foos"
}
Используется instanceOf
, поэтому он должен быть очень быстрым.