我开发了一个scala宏注释,它丰富了具有各种定义的对象(cf. play form macro)。除此之外,我还希望对象包含类型别名
type WFS = FS[_, _, _, _]
获取不同数量的通配符参数。
我已经尝试通过
提取单个通配符类型的值q"type WFS = FS[_]" match { q"type WFS = FS[$t]" => t }
并希望在类型参数列表中使用提取的值(例如q“type WFS = FS [.. $ tplist]”)。但上述陈述产生错误:
scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$t]" => t }
scala.MatchError: type WFS = FS[_$1] forSome {
<synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any
} (of class scala.reflect.internal.Trees$TypeDef)
at .<init>(<console>:15)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43
还有另一种 - 也许更简单 - 构建必要树的方法吗?
答案 0 :(得分:0)
错误是打印您匹配的值的实际形状,显然您需要在匹配的quasiquote中使用相同的形状:
scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$a] forSome { $b }" => println(s"$a --- $b") }
_$1 --- <synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any
如果您想要允许更多参数,而不仅仅是一个参数,最好使用"..$x"
来允许:
scala> q"type WFS = FS[_]" match { case q"type WFS = FS[..$a] forSome { ..$b }" => println(s"$a --- $b") }
List(_$1) --- List(<synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any)
通配符转换为存在 - FS[_]
表示FS[T] forSome { type T }
(有关存在性的详细信息,有“Scala语言规范”,第3.2.10节,“存在类型的占位符语法”)。
当你在匹配的quasiquote中写FS[$a]
时,这意味着“我希望这里有一个类型构造函数应用于一个类型的参数”。但FS[T] forSome { type T }
是一种存在类型,包含类型构造函数的应用程序,因此模式不匹配。
为了更好地理解这一点,并且知道如何调试类似的问题,使用showRaw
查看由quasiquotes生成的树是很有见地的 - 因为这些是类型,我们需要类型quasiquotes,即{{1 }}:
tq"..."
据我了解,与quasiquotes匹配意味着匹配相应的树。所以上面说明了我描述的问题。
令人遗憾的是,quasiquotes并没有隐藏Scala类型系统的这些细节。 这可能是也可能不是quasiquotes的错误,但我不能对此发表评论 - 我猜如果不需要处理就会很酷