类型安全等于宏?

时间:2015-09-19 11:30:22

标签: scala macros equals

对于Scala,是否存在类型安全的等于===实现,其开销超过==?也就是说,与Scalaz和ScalaUtils中的===不同,这是一个使用直接宏来执行检查的实现?

我想在很多地方使用===,但这些都是热点,所以我不希望这会产生额外的运行时成本(比如构建类型等)。

1 个答案:

答案 0 :(得分:0)

基于机械师的答案可能是最好的。这是一个更具有hackish的变体,用于检测推断AnyRefProduct with Serializable或两个不相关的案例类(import scala.collection.breakOut import scala.language.experimental.macros import scala.reflect.macros.blackbox object Implicits { implicit class TripleEquals[A](a: A) { def === [B >: A](b: B): Boolean = macro Macros.equalsImpl[A, B] } } object Macros { private val positiveList = Set("scala.Boolean", "scala.Int", "scala.Long", "scala.Float", "scala.Double", "scala.Option) private val negativeList = Set("java.lang.Object", "java.io.Serializable", "<refinement>") def equalsImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: blackbox.Context) (b: c.Expr[A]): c.Tree = { import c.universe._ val bTpe = weakTypeOf[B] val base = bTpe.baseClasses val names: Set[String] = base.collect { case sym if sym.isClass => sym.fullName } (breakOut) // if a primitive is inferred, we're good. otherwise: if (names.intersect(positiveList).isEmpty) { // exclude all such as scala.Product, scala.Equals val withoutTopLevel = names.filterNot { n => val i = n.lastIndexOf('.') i == 5 && n.startsWith("scala") } // exclude refinements and known Java types val excl = withoutTopLevel.diff(negativeList) if (excl.isEmpty) { c.abort(c.enclosingPosition, s"Inferred type is too generic: `$bTpe`") } } // now simply rewrite as `a == b` val q"$_($a)" = c.prefix.tree q"$a == $b" } } )的典型组合等案例:

Some(1) === Some("hello")

这不适用于更高级别的类型,但是,元组故意失败,而不幸的是{{1}}编译。

修改:内置的a small library,可以对其进行改进,以支持更高级别的类型。