Как полностью избежать отражения во время выполнения в Scala? - PullRequest
0 голосов
/ 02 мая 2018

Примечание Это сообщение предназначено для сообщества, и при необходимости следует добавлять примеры. Если вы не можете напрямую отредактировать ответ, чтобы добавить примеры (примеры проблем или решения), опубликуйте комментарий со ссылкой на суть (или аналогичный) или добавьте отдельный ответ, который будет интегрирован позже.

Существует вероятность того, что Scala 3 может вообще не включать scala.reflect.runtime (в настоящее время Дотти этого не делает, и планы сделать это не определены). Хотя ответы, применимые как к Scala 2, так и к Dotty, могут быть предпочтительнее для целей перехода и для немедленного улучшения производительности, также приветствуются решения для Dotty.

Ссылки

https://www.cakesolutions.net/teamblogs/ways-to-pattern-match-generic-types-in-scala

1 Ответ

0 голосов
/ 03 мая 2018

Общие рекомендации

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, поэтому он должен быть очень быстрым.

...