मान लें कि हम एक मैक्रो लिखना चाहते हैं जो कुछ प्रकार के सदस्यों या विधियों के साथ एक अनाम वर्ग को परिभाषित करता है, और फिर उस वर्ग का एक उदाहरण बनाता है जो सांख्यिकीय रूप से उन विधियों के साथ एक संरचनात्मक प्रकार के रूप में टाइप किया जाता है, आदि। 2.10 में मैक्रो सिस्टम के साथ यह संभव है। 0, और प्रकार का सदस्य हिस्सा बेहद आसान है:
object MacroExample extends ReflectionUtils {
import scala.language.experimental.macros
import scala.reflect.macros.Context
def foo(name: String): Any = macro foo_impl
def foo_impl(c: Context)(name: c.Expr[String]) = {
import c.universe._
val Literal(Constant(lit: String)) = name.tree
val anon = newTypeName(c.fresh)
c.Expr(Block(
ClassDef(
Modifiers(Flag.FINAL), anon, Nil, Template(
Nil, emptyValDef, List(
constructor(c.universe),
TypeDef(Modifiers(), newTypeName(lit), Nil, TypeTree(typeOf[Int]))
)
)
),
Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
))
}
}
(जहां ReflectionUtils
एक सुविधा विशेषता है जो मेरी constructor
विधि प्रदान करती है ।)
यह मैक्रो हमें एक स्ट्रिंग शाब्दिक के रूप में अनाम वर्ग के प्रकार के सदस्य का नाम निर्दिष्ट करने देता है:
scala> MacroExample.foo("T")
res0: AnyRef{type T = Int} = $1$$1@7da533f6
ध्यान दें कि यह उचित रूप से टाइप किया गया है। हम पुष्टि कर सकते हैं कि सब कुछ उम्मीद के मुताबिक काम कर रहा है:
scala> implicitly[res0.T =:= Int]
res1: =:=[res0.T,Int] = <function1>
अब मान लीजिए कि हम एक विधि के साथ एक ही काम करने की कोशिश करते हैं:
def bar(name: String): Any = macro bar_impl
def bar_impl(c: Context)(name: c.Expr[String]) = {
import c.universe._
val Literal(Constant(lit: String)) = name.tree
val anon = newTypeName(c.fresh)
c.Expr(Block(
ClassDef(
Modifiers(Flag.FINAL), anon, Nil, Template(
Nil, emptyValDef, List(
constructor(c.universe),
DefDef(
Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
c.literal(42).tree
)
)
)
),
Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
))
}
लेकिन जब हम इसे आज़माते हैं, तो हमें एक संरचनात्मक प्रकार नहीं मिलता है:
scala> MacroExample.bar("test")
res1: AnyRef = $1$$1@da12492
लेकिन अगर हम एक अतिरिक्त अनाम वर्ग को वहाँ रखते हैं:
def baz(name: String): Any = macro baz_impl
def baz_impl(c: Context)(name: c.Expr[String]) = {
import c.universe._
val Literal(Constant(lit: String)) = name.tree
val anon = newTypeName(c.fresh)
val wrapper = newTypeName(c.fresh)
c.Expr(Block(
ClassDef(
Modifiers(), anon, Nil, Template(
Nil, emptyValDef, List(
constructor(c.universe),
DefDef(
Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
c.literal(42).tree
)
)
)
),
ClassDef(
Modifiers(Flag.FINAL), wrapper, Nil,
Template(Ident(anon) :: Nil, emptyValDef, constructor(c.universe) :: Nil)
),
Apply(Select(New(Ident(wrapper)), nme.CONSTRUCTOR), Nil)
))
}
यह काम करता हैं:
scala> MacroExample.baz("test")
res0: AnyRef{def test: Int} = $2$$1@6663f834
scala> res0.test
res1: Int = 42
यह बेहद आसान है - यह आपको इस तरह की चीजें करने देता है , उदाहरण के लिए- लेकिन मुझे समझ में नहीं आता कि यह क्यों काम करता है, और प्रकार का सदस्य संस्करण काम करता है, लेकिन नहीं bar
। मुझे पता है कि यह परिभाषित व्यवहार नहीं हो सकता है , लेकिन क्या इसका कोई मतलब है? क्या मैक्रो से संरचनात्मक प्रकार (उस पर विधियों के साथ) प्राप्त करने के लिए एक क्लीनर तरीका है?