scala - 多个参数和参数列表的准引用

标签 scala macros scala-macros scala-quasiquotes

Quasiquotes太棒了——它们使在 Scala 中编写宏的痛苦大大减少,而且根据我的经验,它们几乎总是完全按照我的预期工作。最重要的是,它们现在可用 as a plugin在 Scala 2.10 中。

这个问题是关于我写文章时遇到的一个小问题this blog post .当我能找到几分钟的时候,它在我的 list 上,但我想我会把它张贴在这里,以防其他人可以打败我,并帮助其他遇到同样问题的人。

假设我有一个名称-类型对列表:

val pss = List(
  List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
  List(newTermName("z") -> typeOf[String])
)

我想把这些变成一棵树,看起来像这样:
def foo(x: Int, y: Char)(z: String) = ???

以下工作正常:
q"def bar(${pss.head.head._1}: ${pss.head.head._2}) = ???"

也就是说,它构建了以下树:
def bar(x: Int) = ???

这表明我应该能够写出这样的东西:
val quoted = pss.map(_.map { case (n, t) => q"$n: $t" })

q"def foo..${quoted.map(ps => q"($ps)")} = 1"

或者更简单一点,在单个参数列表中有多个参数:
q"def baz(..${quoted.head}) = ???"

两者都不起作用 - 我收到这样的错误:
<console>:28: error: type mismatch;
 found   : List[c.universe.Typed]
 required: List[c.universe.ValDef]
           q"def baz(..${quoted.head}) = ???"
                                ^

很公平——我可以看到准引用器的样子,就像我在构建类型表达式而不是在 quoted 中定义参数一样。 .我能想到的所有明显的事情都没有奏效(添加 = _ ,明确地将准引用输入为 ValDef 等)。

我知道我可以手动构建参数定义:
val valDefs = pss.map(
  _.map {
    case (n, t) => ValDef(Modifiers(Flag.PARAM), n, TypeTree(t), EmptyTree)
  }
)

而现在 baz版本(带有一个参数列表)有效:
q"def baz(..${valDefs.head}) = ???"

但不是 foo版本(具有多个参数列表的版本)。

所以这里有两个问题。首先,如何使用准引号将名称-类型对转换为参数 ValDef在引用参数列表的上下文之外?其次,如何将参数定义列表列表转换为多个参数列表?

对于整个该死的事情,很容易回到手动 AST 构造(参见 my post 示例),但我希望能够使用 quasiquotes 代替。

最佳答案

这是您问题的快速解决方案:

val pss = List(
  List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
  List(newTermName("z") -> typeOf[String])
)
val vparamss: List[List[ValDef]] = pss.map { _.map { case (name, tpe) => q"val $name: $tpe" } }
q"def foo(...$vparamss)"

正如您所看到的,特殊的 ...$splice 允许您定义具有多个参数列表的函数。函数参数本身以与常规 val 相同的方式表示。

另一个例子 ...$it 可能有用:
val xy = List(List(q"x"), List(q"y"))
q"f(...$xy)" // same as q"f(x)(y)"

关于scala - 多个参数和参数列表的准引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18559559/

相关文章:

scala - 以编程方式停止 Alpakka Kafka 流的正确方法

c - 了解 C 位宏

scala - 从 Scala 宏中按名称访问类定义

scala - 如何列出Play Framework 2 Scala应用程序中public/images目录中的所有文件?

java - 序列化对象时包含外部变量

clojure - 在 clojure 宏中评估符号的正确方法

mysql - 如何将相同的 IF 语句应用于同一列中的多个单元格? (Excel)

scala - 如何在 Scala 宏中构造通配符类型?

scala - 具有折叠的抽象类型的模式匹配

mongodb - Scala 根据最大​​值过滤列表