如何在Scala中完全避免运行时反射?

时间:2018-05-02 15:41:03

标签: scala dotty

注意这是一个社区帖子,应根据需要添加示例。如果您无法直接编辑答案以添加示例(问题示例或解决方案),请在评论中发布带有要点(或类似内容)的链接或添加单独的答案,以便稍后集成。

Scala 3可能根本不包含scala.reflect.runtime(Dotty目前还没有,并且计划这样做并不确定)。虽然适用于Scala 2和Dotty的答案可能适用于过渡目的,并且可立即改进性能,但也欢迎使用Dotty特定的解决方案。

参考

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

1 个答案:

答案 0 :(得分:4)

一般建议

TypeTag在编译时生成(由于每个使用站点的宏扩展可能会产生大量的编译时间开销)并在运行时使用,也会产生一些潜在的运行时开销,具体取决于他们的用途。因此,即使在Scala 2中,它们也许应该只是最后的手段(我们希望在这里解决所有这些问题,因此不需要最后的手段)。相比之下,直接或间接使用instanceOf的东西非常快。

使用Java反射

instanceOfsuper fastclassOf(即Java的getClass)几乎一样快。

使用ClassTag

ClassTag上的参照平等也应该非常快。

使用包装类型作为类型类

的实例化

如果可能,您可能需要考虑将类型包装在类中,以赋予其具体的“Java”类型。虽然通常会有开销,但您可以使用value classes

包装类上的类型类通常是公开功能的好方法。顺便说一句,正如@Blaisorblade指出的那样,“类型标签只是一个无法无天的类型(使用方法typeName: Stringtpe: Type)+实例实现”。这将我们带到下一个选项:

如果需要,使用宏

(目前Dotty不支持,但有计划)

虽然可能有点难以习惯,但最终结果应该是使用宏的代码比使用TypeTag时更清晰。此外,宏的使用远远超过TypeTag

选定的例子

匹配集合的类型参数

实施例

来自热门帖子Scala: What is a TypeTag and how do I use it?TypeTag的典型用例是对集合类型执行ad-hoc多态:

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 on gitter(假设我们不需要分别处理不同类型的空列表):

def meth[A](xs: List[A]) = xs match {
   case Nil => "nil"
   case (_: String) :: _ => "list of strings"
   case (_: Foo) :: _ => 'list of foos"
}

这使用instanceOf,所以它应该非常快。