いくつかの型メンバーまたはメソッドで匿名クラスを定義するマクロを記述し、そのクラスのインスタンスを構造型として静的に作成するとします。これらの方法、等これは、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
方法を提供convenience traitある場合。)
このマクロは、匿名クラスの型メンバーの名前を文字列リテラル:
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を知っていますが、意味がありますか?マクロから構造型(その上のメソッドを持つ)を取得する、よりクリーンな方法はありますか?
、マクロでそれを生成するのではなく、REPLで同じコードを記述する場合、それが動作する: スカラ> {最終的なクラスアノン{DEF X = 2}。新しいanon} res1:AnyRef {def x:Int} = anon $ 1 @ 5295c398。レポートをありがとう!私は今週見てみましょう。 –
私は問題[ここ](https://issues.scala-lang.org/browse/SI-6992)を提出したことに注意してください。 –
いいえ、ブロッカーではありません、ありがとう - 余分な匿名クラスのトリックは、私が必要なときはいつでも私のために働いています。私はちょうど質問のアップフォースのカップルに気づき、ステータスについて興味があった。 –