您需要:
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](""))
}
注意,如果省略类型参数,你会得到一个奇怪的错误:
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 类的类型。
更新:如果您可以控制Foo,如何让Creator create Foo 语法工作并返回Foo 的实例。
由于您询问reify 的Any 类型参数,我假设您询问的是类型参数。仅当您希望 Creator.create 的 static 返回类型为 T 而不是 Any 时才有意义;否则,您应该澄清您的问题。
这里的问题与宏无关。 Creator create Foo 将对象Foo 传递给Creator.create,其声明需要通过类型表达式表达Foo.type,类型Foo。 Scala 中的类型表达式非常有限——例如,它们不能使用反射。但是给定一个类型,他们可以选择它的类型成员。
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 = ???
}
这是有限的,因为您需要更改伴随对象,但我很确定您不能做得更好。我不知道,在类型表达式中(在声明 create 的返回类型时可以使用什么来代替 S)从伴随对象获取到其关联的类类型,而且我认为没有。
现在,将上面的内容更改为使用宏很简单:
import language.experimental.macros
import reflect.macros.Context
class Foo[T]
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]): Foo[S] = macro createImpl[S, T]
def createImpl[S: c.AbsTypeTag, T <: Companion[S]: c.AbsTypeTag](c: Context)(obj: c.Expr[T with Companion[S]]): c.Expr[Foo[S]] = {
import c.universe._
reify(new Foo[S]())
}
}