1

对于 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]())
   }
 }

我的问题是将Anyin reify 替换为将返回正确参数化版本的内容。

(上面我使用了一个字符串参数,但在最终版本中,我计划使用类 T 的伴随对象作为标记来了解 Function1[T,Unit] 的参数类型)

4

1 回答 1

2

您需要: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 Aobject A是伴侣,它们的类型是不相关的:第一个有 type A,第二个有 typeA.type其中A是伴侣对象而不是 class 的类型A


更新:如果您可以控制,如何使Creator create Foo语法正常工作并返回. 由于您询问 的类型参数,我假设您询问的是类型参数。仅当您希望静态返回类型为 be而不是时,这才有意义;否则,您应该澄清您的问题。FooFooAnyreifyCreator.createTAny

这里的问题与宏无关。Creator create Foo将对象传递FooCreator.create,其声明需要通过类型表达式来表达,给定Foo.typeFoo类型。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]())
  }
}
于 2012-09-02T15:00:09.343 回答