使用Scala宏无法解释的类型不匹配

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Scala宏无法解释的类型不匹配相关的知识,希望对你有一定的参考价值。

我对以下宏的行为感到困惑:

问题:我正在尝试为case classes上构建的模型编写查询引擎,用户只需指定他希望匹配的字段。

当前的方法:目前,我正在做懒惰的事情,只是利用默认的Scala模式匹配,使用宏来创建适当的match语句。代码如下:

// This is the macro code, defined in project `macros`
import scala.reflect.macros.whitebox

object QueryEngineMacros {
  import scala.language.experimental.macros
  def cimpl(c: whitebox.Context)(cs: c.Expr[CallSite], q: c.Expr[String]): c.Tree = {
    import c.universe._
    val pattern = cq"$q => true"
    q"""$cs match {
      case ${pattern}
      case _ => false
    }"""
  }

  def coincides(cs: CallSite, q: String): Boolean = macro cimpl
}

// This is the engine code, defined in project `queries` (depends on `macros`)
object QueryEngine {
  def apply(q: String, res: ExtractionResult): Seq[CallSite] =
    res.callSites.filter(cs => QueryEngineMacros.coincides(cs, q))
}

错误:这是我第一次使用Scala宏,但一切似乎都很好。它也不会抱怨依赖性。但是,我收到此错误消息:

Error:(27, 66) type mismatch;
 found   : String
 required: some.package.CallSite
    res.callSites.filter(cs => QueryEngineMacros.coincides(cs, q))

有谁知道这可能是什么原因?

编辑:错字修复

答案

对不起,但Scala Macros不这样做。是的Scala宏可以生成新代码,但它们在编译时运行。但你看起来想要的是根据传递给宏的参数q在运行时生成一些代码。这是不可能的。特别是线路

val pattern = cq"$q => true"

不是你期望它做的。您实际生成的宏大致如下:

def apply(q: String, res: ExtractionResult): Seq[CallSite] =
    res.callSites.filter(cs => cs match {
       case q => true
       case _ => false
    })

所以你试着匹配cs类型的CallSiteq类型的String(不是q解释为一段代码!)即你有效地检查cs是否等于q并且编译器看到这个匹配从来都不是真的并说这个给你错误的。

总结一下:如果你的q实际上是编译时常量,那么这样的宏几乎没有任何好处。如果它是一个运行时变量 - 这样的宏只需要帮助。

以上是关于使用Scala宏无法解释的类型不匹配的主要内容,如果未能解决你的问题,请参考以下文章

linux打开终端如何启动scala,如何在终端下运行Scala代码片段?

excel 宏:ByRef 参数类型不匹配

Scala编译器抱怨方法级别的泛型参数的类型不匹配

Scala中的嵌套与展平模式匹配

Scala模式匹配泛型类型擦除问题

类型不匹配。必需:布尔值,在 Scala 中找到:Future[Boolean]