简体   繁体   English

使用宏生成通配符绑定模式

[英]Generate wildcard binding pattern with macros

Scala allows pattern matching on varargs for unapplySeq : Scala允许对unapplySeq varargs进行模式匹配:

case class A(args: String*)

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

I want to generate such pattern with macros. 我想用宏生成这样的模式。 How should I do it? 我该怎么办? A natural thing to try does not work: 自然尝试不起作用:

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

It is possible to extract the actual type from a q pattern, however, and recreate the pattern with it: 但是,可以从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 @ (_)*)

But this is too hacky and I don't want to do it. 但这太hacky了,我不想这么做。

The reason why quasiquotes don't support pq"x @ _*" lies in the way pattern syntax is defined. 准引用不支持pq"x @ _*"在于模式语法的定义方式。 The grammar of the language defines pattern syntax through Pattern production rule. 语言的语法通过Pattern产生规则定义模式语法。 As one can see _* is actually not a valid pattern by itself, it only works inside special Patterns production rule, that is used to model a sequence of patterns inside extractors. 可以看出_*实际上并不是有效的模式,它仅在特殊的Patterns产生规则内起作用,该规则用于对提取器内部的一系列模式进行建模。

Quasiquotes let you plug into different contexts in the grammar through variety of interpolators. 准引用使您可以通过各种插值器插入语法中的不同上下文。 Unfortunately we can not support all possible contexts as this would have caused us to have hundreds of interpolators in the API. 不幸的是,我们不能支持所有可能的上下文,因为这会导致我们在API中拥有数百个插值器。

The simplest solution is indeed to use Star(Ident(termNames.WILDCARD)) here. 实际上,最简单的解决方案是在此处使用Star(Ident(termNames.WILDCARD))

Oh well, I've forgotten about showRaw() : 哦,好了,我忘记了showRaw()

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

Now I'll just make it a constant and use it instead of some literal pattern: 现在,我将其设置为常量并使用它代替某些文字模式:

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

pq"$someIdent @ $wcard"

While awkward, it seems to be the best approach given that quasiquotes do not work. 虽然很尴尬,但鉴于准引用不起作用,这似乎是最好的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM