假設我們要編寫一個宏,該宏定義了具有某些類型成員或方法的匿名類,然後創建該類的實例,該靜態類型爲類型爲結構類型那些方法等等,這是可能的,在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,但它有什麼意義嗎?是否有更簡潔的方法從宏中獲取結構類型(以及其中的方法)?
有趣的是,如果寫在REPL相同的代碼,而不是在一個宏產生它的,它的工作原理: 階> {最終類匿名{DEF X = 2}; new anon} res1:AnyRef {def x:Int} = anon $ 1 @ 5295c398。感謝報告!我會在這個星期看看。 –
請注意,我已在[此處]提交了一個問題(https://issues.scala-lang.org/browse/SI-6992)。 –
不是,不是一個封鎖,謝謝 - 額外的匿名類技巧在我需要的時候爲我工作。我剛纔注意到了一些關於這個問題的提議,並對這個地位感到好奇。 –