【问题标题】:Why value method cannot be used outside macros?为什么值方法不能在宏之外使用?
【发布时间】:2020-08-10 02:37:39
【问题描述】:

错误信息

`value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.
val x = version.value
                ^

明确指出如何解决问题,例如使用:=

val x = settingKey[String]("")
x := version.value

sbt uses macros heavily状态中的解释

value 方法本身实际上是一个宏,如果你调用它 在另一个宏的上下文之外,将导致编译时间 错误,确切的错误信息是... 你可以看到为什么,因为 sbt 设置完全是声明性的,你 无法从键中访问任务的值,这没有意义 这样做。

但是我很困惑 sbt 的声明性性质是什么意思。例如,直觉上我会认为以下 vanilla Scala sn-p 在语义上类似于 sbt 的

def version: String = ???
lazy val x = s"Hello $version"  // ok

trait Foo {
  def version: String
  val x = version               // ok
}

由于这是合法的,显然 Scala sn-p 在语义上并不等同于 sbt。我想知道是否有人可以详细说明为什么value 不能在宏之外使用?原因纯粹是与宏语法相关的语法,还是我遗漏了一些关于 sbt 本质的基本知识?

【问题讨论】:

    标签: scala sbt scala-macros


    【解决方案1】:

    正如另一句话所说的那样

    定义 sbt 的任务引擎是通过给 sbt 一系列设置来完成的,每个设置都声明一个任务实现。 sbt 然后按顺序执行这些设置。任务可以通过多个设置多次声明,最后执行的获胜。

    所以在上线的那一刻

    val x = version.value
    

    将被执行(如果允许的话!),整个程序仍在设置中,SBT 不知道version 的最终定义。

    从什么意义上说,程序“仍在建立中”?

    SBT 的操作顺序基本上是(可能遗漏了什么):

    1. 您的所有 Scala 构建代码都已运行。
    2. 它包含一些设置和任务定义,SBT 在遇到时收集它们(以及来自核心、插件等的)
    3. 它们按拓扑排序到任务图中、去重(“最后执行的获胜”)等。
    4. 评估设置。
    5. 现在您可以实际运行任务(例如从 SBT 控制台)。

    version.value 仅在第 4 步之后可用,但val x = version.value 在第 1 步运行。

    惰性求值不会解决这个问题吗?

    好吧,当你写val x = ... 时,没有惰性求值。但是lazy val x = ... 也在第 1 步运行。

    【讨论】:

      猜你喜欢
      • 2012-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      相关资源
      最近更新 更多