【问题标题】:Macro return type depends on the arguments宏返回类型取决于参数
【发布时间】:2014-02-24 06:49:36
【问题描述】:

我想编写一个返回类型取决于参数的宏。简化示例:

def fun[T](methodName: String) = macro funImpl[T]

def funImpl[T: WeakTypeTag](c: Context)(methodName: c.Expr[String]): /* c.Expr[T => return type of T.methodName] */ = {
  // return x => x.methodName
}

显然funImpl 的注释掉返回类型是非法的。我试过简单地返回一个Tree,但这会产生一个错误:

[error] macro implementation has wrong shape:
[error]  required: (c: scala.reflect.macros.Context): c.Expr[Any]
[error]  found   : (context: scala.reflect.macros.Context): context.Tree
[error] type mismatch for return type: c.universe.Tree does not conform to c.Expr[Any]
[error]     def fun[T] = macro PrivateMethodMacro.funImpl[T]
[error]                                          ^

可以写这样的宏吗?显然,如果返回类型作为另一个类型参数传递,就像Is it possible to write a scala macro whose returntype depends on argument? 的答案一样,但这不是我想要的。

【问题讨论】:

    标签: scala scala-macros


    【解决方案1】:

    是的,这是可能的,这要归功于whitebox macros 的魔力:你可以告诉编译器返回类型是c.Expr[Any],它会推断出更精确的类型。

    这种行为shocked me when I first ran into it——它非常、非常强大并且非常、非常可怕——但它绝对是有意的,并且将继续受到支持,尽管 2.11 将区分白盒和黑盒宏,而前者很可能保持更长时间的实验状态(如果他们完全离开的话)。

    例如,以下是您所要求内容的快速草图(我在此处通过 macro paradise plugin 使用 quasiquotes 用于 2.10,但如果没有准引号,它只会更加冗长):

    import scala.language.experimental.macros
    import scala.reflect.macros.Context
    
    def funImpl[T: c.WeakTypeTag](c: Context)(
      method: c.Expr[String]
    ): c.Expr[Any] = {
      import c.universe._
    
      val T = weakTypeOf[T]
    
      val methodName: TermName = method.tree match {
        case Literal(Constant(s: String)) => newTermName(s)
        case _ => c.abort(c.enclosingPosition, "Must provide a string literal.")
      }
    
      c.Expr(q"(t: $T) => t.$methodName")
    }
    
    def fun[T](method: String) = macro funImpl[T]
    

    然后:

    scala> fun[String]("length")
    res0: String => Int = <function1>
    

    您可以看到推断的类型正是您想要的,而不是Any。您可以(并且可能应该)将funImpl 的返回类型设置为c.Expr[T =&gt; Any] 并返回类似c.Expr[T =&gt; Any](q"_.$methodName") 的内容,但这基本上只是文档——它对如何推断宏的返回类型没有任何影响在这种情况下。

    【讨论】:

    • 在 2.11 中,warning: macro defs must have explicitly specified return types (inference of Any from macro impl's c.Expr[Any] is deprecated and is going to stop working in 2.12)
    • 你在使用whitebox包中的上下文吗?
    • 当然。未区分的上下文更加被弃用。
    • 即使在 2.12.8 中也显示为已弃用,但它仍在工作。我想知道为什么他们不赞成它,因为它是如此强大。编辑:他们似乎正在转向可以替换无类型宏的宏注释,但绝对不是那么容易使用
    猜你喜欢
    • 2021-07-18
    • 2022-01-09
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    相关资源
    最近更新 更多