对于DSL,我希望能够做到这样的事情:
object Creator {
def create[T](s :String) :Foo[T] = macro createImpl[T]
def createImpl[T](c :Context)(s :c.Expr[String]) : c.Expr[Foo[T]] = {
reify(new Foo[Any]())
}
}
我的问题是将reify中的Any
替换为将返回正确参数化版本的内容。
(上面我使用字符串参数,但在最终版本中,我打算使用T类的伴随对象作为标记来了解Function1 [T,Unit]的参数类型)
答案 0 :(得分:2)
你需要:
a)写new Foo[T]()
而不是new Foo[Any]()
(简单)
b)通过使用上下文绑定声明参数T
来向宏传递类型AbsTypeTag[T]
的表示,即类型T
的值:[T: c.AbsTypeTag]
。
这是我在Scala 2.10.0-M7中测试过的代码。 修改即可。在2.10.0-RC1 AbsTypeTag
已重命名为WeakTypeTag
。关于宏和类型标签的其他所有内容都保持不变。
Creator.scala:
import language.experimental.macros
import reflect.macros.Context
class Foo[T]
object Creator {
def create[T](s: String): Foo[T] = macro createImpl[T]
def createImpl[T: c.AbsTypeTag](c: Context)(s: c.Expr[String]): c.Expr[Foo[T]] = {
import c.universe._
reify(new Foo[T]())
}
}
MacroClient.scala:
object Main extends App {
println (Creator.create[Int](""))
}
请注意,如果省略type参数,您将收到一个奇怪的错误:
scala> Creator.create[Int]("")
res2: Foo[Int] = Foo@4888884e
scala> Creator.create("")
<console>:12: error: macro has not been expanded
Creator.create("")
^
你也写道:
(上面我使用字符串参数,但在我计划使用的最终版本中 T类的伴随对象作为知道参数类型的标记 一个Function1 [T,Unit])
但如果我做对了,这听起来像个坏主意。调用语法不是写Creator.create[T](otherArgs)
,而是Creator.create(T, otherArgs)
,而不是一个很大的优点(如果有的话)。但是你甚至无法获得后一种语法:如果class A
和object A
是随播广告,则其类型不相关:第一种类型为A
,第二种类型为A.type
} A
是伴随对象,而不是类A
的类型。
更新:如果您可以控制Creator create Foo
,如何使Foo
语法生效并返回Foo
的实例。
由于您询问Any
的{{1}}类型参数,我假设您询问的是类型参数。只有当您希望reify
的静态返回类型为Creator.create
而不是T
时才有意义;否则,你应该澄清你的问题。
这里的问题与宏没什么关系。 Any
将对象Creator create Foo
传递给Foo
,其声明需要通过类型表达式给出Creator.create
类型Foo.type
。 Scala中的类型表达式非常有限 - 例如,它们不能使用反射。但是给定一个类型,他们可以选择其类型成员。
Foo
这是有限的,因为你需要改变伴侣对象,但我很确定你不能做得更好。我不知道,在类型表达式中(在声明返回类型trait Companion[Class]
//How to declare a companion
class Foo
object Foo extends Companion[Foo]
/*I'm cheating: an implementation of Companion does not need to be a true Companion. You can add documentation to explain how Companion is supposed to be used. */
object Bar extends Companion[Foo]
//But this is also useful - you can't create your own companion objects for pre-existing types, but you can still create the right instances of Companion:
object pInt extends Companion[Int]
object Creator {
//T with Companion[S] is needed to workaround a type inference bug (SI-5298) and allow S to be correctly inferred.
def create[S, T <: Companion[S]](obj: T with Companion[S]): S = ???
}
时,可以用来代替S
)从同伴对象获取到其关联对象类型一般,我认为没有。
现在,将上面的内容更改为使用宏很简单:
create