1

Scala 允许对 varargs 进行模式匹配unapplySeq

case class A(args: String*)

A("a", "b", "c") match {
  case A(args @ _*) => args  // Seq("a", "b", "c")
}

我想用宏生成这样的模式。我该怎么做?一个自然的尝试是行不通的:

scala> pq"x @ _*"
<console>:11: error: illegal start of simple pattern
              pq"x @ _*"
                       ^

但是,可以从q模式中提取实际类型,然后用它重新创建模式:

scala> val q"??? match { case Hello($ident @ $thingy) => }" = q"??? match { case Hello(any @ _*) => }"
ident: reflect.runtime.universe.Name = any
thingy: reflect.runtime.universe.Tree = (_)*

scala> pq"$ident @ $thingy"
res1: reflect.runtime.universe.Bind = (any @ (_)*)

但这太hacky了,我不想这样做。

4

2 回答 2

1

quasiquotes 不支持的原因pq"x @ _*"在于模式语法的定义方式。语言的Pattern语法通过产生式规则定义模式语法。正如人们所看到_*的,它本身实际上并不是一个有效的模式,它只在特殊Patterns的生产规则内工作,用于对提取器内的一系列模式进行建模。

Quasiquotes 允许您通过各种插值器插入语法中的不同上下文。不幸的是,我们不能支持所有可能的上下文,因为这会导致我们在 API 中有数百个插值器。

最简单的解决方案确实是在Star(Ident(termNames.WILDCARD))这里使用。

于 2015-02-20T12:26:48.123 回答
0

哦,好吧,我忘记了showRaw()

scala> showRaw(thingy)
res0: String = Star(Ident(termNames.WILDCARD))

现在我将使它成为一个常量并使用它而不是一些文字模式:

val wcard = Star(Ident(termNames.WILDCARD))

pq"$someIdent @ $wcard"

虽然尴尬,但考虑到准引号不起作用,这似乎是最好的方法。

于 2015-02-19T20:28:30.110 回答