7

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

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

参考

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

4

1 回答 1

7

一般建议

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

使用 Java 反射

instanceOf超级快。classOf(即 Java 的getClass)几乎一样快。

使用 ClassTag

s上的引用相等ClassTag也应该非常快。

使用包装类型作为类型类的实例化

如果可能,您可能需要考虑将您的类型包装在一个类中,给它一个具体的“Java”类型。虽然通常会有开销,但您可以使用值类

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

如果需要,使用宏

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

虽然可能有点难以习惯,但最终结果应该是使用宏的代码中的语法比使用TypeTag. 此外,宏的用途远远超出TypeTag.

精选示例

匹配集合的类型参数

例子

的一个典型用例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" 

解决方案

这是来自 gitter 上的@smarter(假设我们不需要单独处理不同类型的空列表):

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

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

于 2018-05-03T17:52:45.813 回答