से अज्ञात वर्ग के तरीकों के साथ एक संरचनात्मक प्रकार प्राप्त करना मान लीजिए कि हम एक मैक्रो लिखना चाहते हैं जो किसी प्रकार के सदस्यों या विधियों के साथ किसी अज्ञात वर्ग को परिभाषित करता है, और उसके बाद उस वर्ग का एक उदाहरण बनाता है जो स्थिर रूप से संरचनात्मक प्रकार के रूप में टाइप किया गया है उन तरीकों, आदि यह 2.10.0 में मैक्रो प्रणाली के साथ संभव है, और प्रकार सदस्य हिस्सा बहुत आसान है: (। कहाँ ReflectionUtils
एक convenience trait कि मेरे constructor
तरीका प्रदान करता है है)मैक्रो
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)
))
}
}
यह मैक्रो हमें अज्ञात वर्ग के प्रकार के सदस्य के नाम को निर्दिष्ट करने देता है एक स्ट्रिंग शाब्दिक:
scala> MacroExample.foo("T")
res0: AnyRef{type T = Int} = [email protected]
ध्यान दें कि यह उचित रूप से टाइप किया गया है। हम पुष्टि कर सकते हैं कि सब कुछ काम कर रहा है के रूप में उम्मीद:
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 = [email protected]
लेकिन हम वहाँ में एक अतिरिक्त गुमनाम वर्ग छड़ी अगर:
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} = [email protected]
scala> res0.test
res1: Int = 42
यह बहुत आसान-यह आप this जैसी चीज़ें कर के लिए देता है उदाहरण-लेकिन मुझे समझ नहीं आता क्यों यह काम करता है, और प्रकार सदस्य संस्करण में काम करता है, लेकिन नहीं bar
। मुझे यह may not be defined behavior पता है, लेकिन क्या यह कोई समझ में आता है? एक मैक्रो से संरचनात्मक प्रकार (इसके तरीकों के साथ) पाने के लिए एक क्लीनर तरीका है?
दिलचस्प बात यह है, तो आप के बजाय आरईपीएल में एक ही कोड लिखने एक मैक्रो में यह पैदा करने में, यह काम करता है: स्केला> {अंतिम वर्ग anon {डीईएफ़ x = 2}; नया एनन} res1: AnyRef {def x: Int} = anon $ 1 @ 5295c398। रिपोर्ट के लिए धन्यवाद! मैं इस सप्ताह एक नज़र डालेगा। –
ध्यान दें कि मैंने एक मुद्दा दायर किया है [यहां] (https://issues.scala-lang.org/browse/SI-6992)। –
नहीं, अवरोधक नहीं, धन्यवाद- जब भी मुझे इसकी आवश्यकता होती है तो अतिरिक्त अज्ञात वर्ग चाल मेरे लिए काम करती है। मैंने अभी सवाल पर कुछ उपरोक्त विचारों को देखा और स्थिति के बारे में उत्सुक था। –