मशीनिनिस्ट पर आधारित उत्तर शायद सबसे अच्छा है।
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"
}
}
यह उच्च kinded प्रकार के साथ काम नहीं करता है, फिर भी, इसलिए tuples: यहाँ एक और अधिक hackish संस्करण है कि इस तरह Any
या AnyRef
या दो असंबंधित मामले वर्गों (Product with Serializable
) के विशिष्ट मिश्रण का निष्कर्ष निकालते के रूप में मामलों का पता लगाता है दुर्भाग्यवश Some(1) === Some("hello")
संकलित करते समय जानबूझ कर असफल हो रहे हैं।
संपादित: एक अंतर्निहित a small library है कि इस पर सुधार उच्च kinded प्रकारों का समर्थन करने के लिए।
स्रोत
2016-04-23 22:15:55
एक मैक्रो कार्यान्वयन आपको एक अंतर्निहित मूल्य वर्ग पर क्या खरीदता है? –
@TravisBrown मूल्य वर्ग आवंटन लागत को बचाते हैं, लेकिन अगर मैं गलत नहीं हूं, तो इंडिकेशन लागत को न बचाएं। यह प्रासंगिक हो सकता है: http://typelevel.org/blog/2015/08/06/machinist.html –