使用宏生成通配符绑定模式
Generate wildcard binding pattern with macros
Scala 允许对 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了,我不想做。
哦,我忘了 showRaw()
:
scala> showRaw(thingy)
res0: String = Star(Ident(termNames.WILDCARD))
现在我将它设为常量并使用它来代替某些文字模式:
val wcard = Star(Ident(termNames.WILDCARD))
pq"$someIdent @ $wcard"
虽然笨拙,但鉴于准引号不起作用,这似乎是最好的方法。
准引号不支持pq"x @ _*"
的原因在于模式语法的定义方式。 The grammar of the language 通过 Pattern
生产规则定义模式语法。正如你所看到的,_*
实际上本身并不是一个有效的模式,它只在特殊的 Patterns
生产规则中起作用,该规则用于在提取器中对一系列模式进行建模。
准引号让您可以通过各种插值器插入语法中的不同上下文。不幸的是,我们不能支持所有可能的上下文,因为这会导致我们在 API.
中有数百个插值器
最简单的解决方案确实是在这里使用 Star(Ident(termNames.WILDCARD))
。
Scala 允许对 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了,我不想做。
哦,我忘了 showRaw()
:
scala> showRaw(thingy)
res0: String = Star(Ident(termNames.WILDCARD))
现在我将它设为常量并使用它来代替某些文字模式:
val wcard = Star(Ident(termNames.WILDCARD))
pq"$someIdent @ $wcard"
虽然笨拙,但鉴于准引号不起作用,这似乎是最好的方法。
准引号不支持pq"x @ _*"
的原因在于模式语法的定义方式。 The grammar of the language 通过 Pattern
生产规则定义模式语法。正如你所看到的,_*
实际上本身并不是一个有效的模式,它只在特殊的 Patterns
生产规则中起作用,该规则用于在提取器中对一系列模式进行建模。
准引号让您可以通过各种插值器插入语法中的不同上下文。不幸的是,我们不能支持所有可能的上下文,因为这会导致我们在 API.
中有数百个插值器最简单的解决方案确实是在这里使用 Star(Ident(termNames.WILDCARD))
。