समस्या यह है कि आपके द्वारा reify
पर जाने वाला कोड अनिवार्य रूप से उस बिंदु पर वर्बैटिम रखा जा रहा है जहां मैक्रो का विस्तार किया जा रहा है, और fieldMemberType
का अर्थ कुछ भी नहीं है।
कुछ मामलों में आप splice
का उपयोग उस अभिव्यक्ति को छिपाने के लिए कर सकते हैं जो आपके द्वारा संशोधित कोड में मैक्रो-विस्तार समय पर है। उदाहरण के लिए, अगर हम इस विशेषता का एक उदाहरण बनाने के लिए कोशिश कर रहे थे:
reify { new Foo { def i = c.literal(myInt).splice } }
:
val myInt = 10
हम निम्नलिखित लिख सकते हैं:
trait Foo { def i: Int }
और वृहद विस्तार समय में इस चर था
यह यहां काम नहीं करेगा, जिसका मतलब है कि आपको अच्छे छोटे reify
के बारे में भूलना होगा और हाथ से एएसटी लिखना होगा। दुर्भाग्यवश, आप पाएंगे कि यह बहुत कुछ होता है।
import scala.reflect.runtime.universe._
trait TypeBuilder { type fieldType }
showRaw(reify(new TypeBuilder { type fieldType = String }))
यह एएसटी की कई लाइनों, जिसे फिर आप कट जाता है और एक प्रारंभिक बिंदु के रूप में अपने मैक्रो परिभाषा में चिपका सकते हैं थूक से बाहर होगा: मेरा मानक दृष्टिकोण एक नया आरईपीएल शुरू करने और कुछ इस तरह टाइप करने के लिए है। तो फिर तुम इसके साथ बेला, इस तरह बातें की जगह:
Ident(TypeBuilder)
इस के साथ
:
Ident(newTypeName("TypeBuilder"))
और Flag.FINAL
साथ FINAL
, और इतने पर। मेरी इच्छा है कि एएसटी प्रकारों के लिए toString
विधियों को उनके द्वारा बनाए जाने वाले कोड के लिए बिल्कुल सटीक रूप से मेल किया जाए, लेकिन आपको बहुत जल्दी समझने की आवश्यकता होगी कि आपको क्या बदलना है।
c.Expr(
Block(
ClassDef(
Modifiers(Flag.FINAL),
anon,
Nil,
Template(
Ident(newTypeName("TypeBuilder")) :: Nil,
emptyValDef,
List(
constructor(c),
TypeDef(
Modifiers(),
newTypeName("fieldType"),
Nil,
TypeTree(fieldMemberType)
)
)
)
),
Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
)
)
कहाँ anon
आप अपनी गुमनाम वर्ग के लिए पहले से बनाए जा चुके प्रकार का नाम है, और constructor
एक सुविधा की विधि मैं बात एक छोटे से इस तरह का बनाने के लिए उपयोग है: आप कुछ इस तरह से खत्म हो जाएगा कम घृणास्पद (आप this complete working example के अंत में इसकी परिभाषा पा सकते हैं)।
अब अगर हम this की तरह कुछ में इस अभिव्यक्ति लपेट, हम निम्नलिखित लिख सकते हैं:
scala> TypeMemberExample.builderWithType[String]
res0: TypeBuilder{type fieldType = String} = [email protected]
तो यह काम करता है।हमने c.universe.Type
(जिसे मैं WeakTypeTag
से builderWithType
पर टाइप पैरामीटर के यहां से प्राप्त करता हूं, लेकिन यह किसी भी पुराने Type
के साथ ठीक उसी तरह काम करेगा) और हमारे TypeBuilder
विशेषता के प्रकार के सदस्य को परिभाषित करने के लिए इसका उपयोग किया गया है।
सिर्फ एक प्रश्न, "newTypeName" प्रकार को कैसे पाता है? मेरा मतलब है कि यह कैसे पता चलता है कि यह पैकेज कौन सा है? – mgonto
धन्यवाद! और 'newTypeName' प्रकार का शिकार नहीं करता है-यह सिर्फ उस स्ट्रिंग की प्रतिलिपि बनाता है जिसे आप इसे उस कोड में देते हैं जो मैक्रो उत्पन्न कर रहा है, जिसे तब सामान्य रूप से संकलक द्वारा टाइप-चेक किया जाएगा। यदि आपको पैकेज निर्दिष्ट करने की आवश्यकता है तो आप लिख सकते हैं उदा। 'चुनें (पहचान ("पैकेज"), newTypeName ("MyClass")) '। –
आप जिस कोड में रुचि रखते हैं उसके कोड के स्निपेट बनाने वाले कोड को प्राप्त करने के लिए आप '-Yreify-copypaste' और/या' showRaw' का उपयोग कर सकते हैं। –