您需要:a)编写new Foo[T]()
而不是(简单)b)通过使用上下文绑定声明参数来new Foo[Any]()
在宏中传递 type 的表示T
,即 type 的值: 。AbsTypeTag[T]
T
[T: c.AbsTypeTag]
这是我在 Scala 2.10.0-M7 中测试的代码。编辑. 在 2.10.0-RC1AbsTypeTag
中已重命名为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
是伴侣,它们的类型是不相关的:第一个有 type A
,第二个有 typeA.type
其中A
是伴侣对象而不是 class 的类型A
。
更新:如果您可以控制,如何使Creator create Foo
语法正常工作并返回. 由于您询问 的类型参数,我假设您询问的是类型参数。仅当您希望静态返回类型为 be而不是时,这才有意义;否则,您应该澄清您的问题。Foo
Foo
Any
reify
Creator.create
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 = ???
}
这是有限的,因为您需要更改伴随对象,但我很确定您不能做得更好。我不知道,在一个类型表达式S
中(在声明 的返回类型时你可以用它来代替create
)从一个伴随对象到它的关联类类型,我不认为有一个。
现在,将上面的内容更改为使用宏很简单:
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]())
}
}