我在我的 Scala 代码中使用 RunningStrategies 类来定义一组运行策略。为了创建 RunningStrategies 的实例,我使用了 apply 方法以及代表不同策略的可变数量的参数。为此,我还定义了一个名为 RunningStrategiesMacros 的宏。
但是,当我尝试将 RunningStrategies 与某些策略一起使用时,我收到以下错误消息:“找不到宏实现:应用”。该错误似乎与我试图在定义它的同一编译运行中使用宏实现有关。
跑步策略:
package com.dv.phoenix.brandsafety.models
object RunningStrategy extends Enumeration {
type RunningStrategy = Value
val
MonitoringOnly,
BlockingOnly,
MonitoringAndBlockingInherent,
MonitoringAndBlockingRecalculate
= Value
}
跑步策略:
package com.dv.phoenix.brandsafety.models
import com.dv.phoenix.brandsafety.models.RunningStrategy.RunningStrategy
import com.dv.phoenix.brandsafety.utils.RunningStrategiesMacros
import scala.language.experimental.macros
case class RunningStrategies private (runningStrategies: Set[RunningStrategy])
object RunningStrategies {
def apply(strategies: RunningStrategy*): RunningStrategies = macro RunningStrategiesMacros.applyImp
}
RunningStrategiesMacro:
package com.dv.phoenix.brandsafety.utils
import com.dv.phoenix.brandsafety.models.RunningStrategies
import com.dv.phoenix.brandsafety.models.RunningStrategy.RunningStrategy
import scala.reflect.macros.blackbox
object RunningStrategiesMacros {
def applyImp(c: blackbox.Context)(strategies: c.Expr[RunningStrategy]*): c.Expr[RunningStrategies] = {
import c.universe._
val strategySet = strategies.map(_.tree).toList
if (strategySet.contains(q"MonitoringAndBlockingInherent") && strategySet.contains(q"MonitoringAndBlockingRecalculate")) {
c.abort(c.enclosingPosition, "MonitoringAndBlockingInherent and MonitoringAndBlockingRecalculate cannot be used together")
}
val runningStrategies = q"RunningStrategies(Set(..$strategySet))"
c.Expr[RunningStrategies](runningStrategies)
}
}
用法:
override protected val runningStrategies: RunningStrategies = RunningStrategies(MonitoringOnly, MonitoringAndBlockingInherent, MonitoringAndBlockingRecalculate)
我收到以下错误:
macro implementation not found: apply
(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
override protected val runningStrategies: RunningStrategies = RunningStrategies(MonitoringOnly, MonitoringAndBlockingInherent, MonitoringAndBlockingRecalculate)
我注意到 scala-logging 库已经设法用他们的 LoggerImpl 和 LoggerMacro 类解决了这个问题。有人可以解释他们是如何做到这一点的,以及我如何将相同的技术应用于我的 RunningStrategiesMacro?
在您的问题中,您描述了您的包结构,但没有描述您的项目结构。包和子项目是不同的概念
为什么sbt/assembly在有多个子项目的项目中找不到主类?
如果你想在 Scala 2 中使用 macros,你应该有不同的子项目
https://www.scala-sbt.org/1.x/docs/Macro-Projects.html
首先,让我们刷新一下术语。这是一个宏定义
import scala.language.experimental.macros
def foo(): Unit = macro fooImpl
这是一个宏实现
import scala.reflect.macros.blackbox
def fooImpl(c: blackbox.Context)(): c.Tree = {
import c.universe._
println("test")
q"""_root_.scala.Predef.println("foo")"""
}
这是一个宏应用程序
foo()
// at compile time: scalac: test
// at runtime: foo
在 Scala 2 中,宏实现必须在宏应用程序之前编译(宏应用程序的编译时,即宏扩展是宏的运行时)。所以宏 implementations 和宏 applications 必须在不同的编译单元中。例如在您项目的不同子项目中。或者在同一项目的
src/main/scala
和src/test/scala
中(主要代码在测试之前编译)。宏定义在哪里并不那么重要。它们可以在与宏实现相同的编译单元/子项目中(可能在相同的文件/类中)或与宏应用程序相同或在它们自己的中。
scala-logging
中,宏定义
def error(message: String): Unit = macro LoggerMacro.errorMessage
和宏实现
def errorMessage(c: LoggerContext)(message: c.Expr[String]): c.universe.Tree = ...
在同一个项目中(在不同的文件中但这不是必需的,它们可以在同一个文件中)但是宏应用程序
logger.error(msg)
在
src/test/scala
https://github.com/lightbend-labs/scala-logging/blob/v3.9.5/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala。其他宏应用程序也将在不同的编译单元中,即使用 scala-logging
作为依赖项的客户端项目。
在你的项目中
def apply(strategies: RunningStrategy*): RunningStrategies = macro RunningStrategiesMacros.applyImp
是宏定义并且
def applyImp(c: blackbox.Context)(strategies: c.Expr[RunningStrategy]*): c.Expr[RunningStrategies] = ...
是宏实现。但是你应该重新组织你的项目至少有两个子项目并放置宏应用程序
override protected val runningStrategies: RunningStrategies = RunningStrategies.apply(MonitoringOnly, MonitoringAndBlockingInherent, MonitoringAndBlockingRecalculate)
到不同的子项目。