यह एक ऐसा उत्तर है जो फेडेरिको की तकनीक पर भिन्नता दिखाता है, यदि आप एक स्थिर एनोटेशन का उपयोग करना चाहते हैं जिसमें वैकल्पिक नाम तर्क हैं। उस स्थिति में, आपको मामले मिलान विवरण में संभावित आमंत्रण अभिव्यक्तियों पर विचार करने की आवश्यकता है। एक वैकल्पिक तर्क का स्पष्ट रूप से नाम दिया जा सकता है, इसे किसी नाम के बिना दिया जा सकता है, या यह मौजूद नहीं हो सकता है। इनमें से प्रत्येक c.prefix.tree
में एक अलग पैटर्न के रूप में संकलित समय पर दिखाया गया है, जैसा कि नीचे दिखाया गया है।
@compileTimeOnly("Must enable the Scala macro paradise compiler plugin to expand static annotations")
class noop(arg1: Int, arg2: Int = 0) extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro AnnotationMacros.noop
}
class AnnotationMacros(val c: whitebox.Context) {
import c.universe._
// an annotation that doesn't do anything:
def noop(annottees: c.Expr[Any]*): c.Expr[Any] = {
// cases for handling optional arguments
val (arg1q, arg2q) = c.prefix.tree match {
case q"new noop($arg1, arg2 = $arg2)" => (arg1, arg2) // user gave named arg2
case q"new noop($arg1, $arg2)" => (arg1, arg2) // arg2 without name
case q"new noop($arg1)" => (arg1, q"0") // arg2 defaulted
case _ => c.abort(c.enclosingPosition, "unexpected annotation pattern!")
}
// print out the values
println(s"arg1= ${evalTree[Int](arg1q)} arg2= ${evalTree[Int](arg2q)}")
// just return the original annotee:
annottees.length match {
case 1 => c.Expr(q"{ ${annottees(0)} }")
case _ => c.abort(c.enclosingPosition, "Only one annottee!")
}
}
def evalTree[T](tree: Tree) = c.eval(c.Expr[T(c.untypecheck(tree.duplicate)))
}
यहाँ एक उदाहरण मंगलाचरण कि नाम arg2
है, और इसलिए यह पहली बार पैटर्न से मेल खाएगी - case q"new noop($arg1, arg2 = $arg2)"
- ऊपर:
object demo {
// I will match this pattern: case q"new noop($arg1, arg2 = $arg2)"
@noop(1, arg2 = 2)
trait someDeclarationToAnnotate
}
भी ध्यान रखें कि क्योंकि जिस तरह से इन पैटर्न काम की है, तो आप के लिए है स्पष्ट रूप से मैक्रो कोड के अंदर डिफ़ॉल्ट तर्क मान की आपूर्ति करें, जो दुर्भाग्य से थोड़ा हैकी है, लेकिन अंतिम मूल्यांकन कक्षा आपके लिए उपलब्ध नहीं है।
एक प्रयोग के रूप में, मैंने वास्तव में evalTree[scope.of.class.noop](c.prefix.tree)
पर कॉल करके कक्षा बनाने की कोशिश की, लेकिन स्कैला कंपाइलर एक त्रुटि फेंकता है क्योंकि यह माना जाता है कि एनोटेशन मैक्रो कोड के अंदर एनोटेशन का संदर्भ अवैध है।
यह समाधान दिलचस्प है लेकिन किसी कारण से यह मेरे लिए "हैकी" लगता है। इसके अलावा, मैं चाहता हूं कि '' b'' प्रकार का होना चाहिए, किसी भी प्रकार का नहीं। किसी की तरह '' @ फू ("एएए") '' कह सकता है और लगता है कि उनका कोड कन्स्ट्रक्टर के हस्ताक्षर को देखकर संकलित होगा। इसके अलावा, अगर मैं और तर्क जोड़ने का फैसला करता हूं तो यह और अधिक भ्रमित हो जाएगा। लेकिन यह समाधान काम करता है, तो धन्यवाद! –
उत्तर आपकी चिंताओं को दर्शाने के लिए संपादित किया गया। –
यह कोड अब संकलित नहीं करता है। जब आप बूलियन से किसी भी पैरामीटर का प्रकार बदलते हैं, तो सब कुछ ठीक है। त्रुटि संदेश यह है: '' प्रकार की नल की अभिव्यक्ति अंतर्निहित रूपांतरण के लिए अयोग्य है ' –