ধরা যাক আমরা এমন ম্যাক্রো লিখতে চাই যা কিছু ধরণের সদস্য বা পদ্ধতির সাথে একটি বেনাম শ্রেণীর সংজ্ঞা দেয় এবং তারপরে সেই শ্রেণীর একটি উদাহরণ তৈরি করে যা স্টাট্যালি স্ট্রাকচারাল ধরণের হিসাবে methods পদ্ধতিগুলির সাথে টাইপ করা হয়, ইত্যাদি। এটি ম্যাক্রো সিস্টেমের মাধ্যমে 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
। আমি জানি এটি সংজ্ঞায়িত আচরণ নয় , তবে এটি কোনও অর্থবোধ করে? কোনও ম্যাক্রো থেকে কাঠামোগত ধরণের (এটির পদ্ধতিগুলি সহ) পাওয়ার কী ক্লিনার উপায় আছে?