Gradle 构建脚本中这些仅包含标识符的 Groovy 闭包是什么?

问题描述 投票:0回答:2

阅读 Gradle 构建脚本我不断遇到这样的代码

configurations {
  myConfig
}

我明白这段代码用闭包

configurations
调用函数
{ myConfig }
。但那是什么样的闭包体呢?它只是引用了一些未定义的东西,叫做
myConfig
。这个闭包在运行时是如何做的?毕竟下面的代码

def myClosure = { foo }
myClosure()

可预测的产量

Caught: groovy.lang.MissingPropertyException: No such property: foo for class: Main
.

gradle groovy closures
2个回答
0
投票

在 Groovy 中,您可以将 delegates 分配给闭包,这些对象将用于解析闭包中使用的属性和方法。

一个例子是将一个映射分配给闭包

def map = [foo: "bar"]

def myClosure = { foo }
myClosure.delegate = map
myClosure()

这将打印

foo
.

使用 Groovy Web 控制台试试

Delegates 也可以实现 methodMissingpropertyMissing 来对动态属性做出反应。


0
投票

Groovy 在省略括号时看起来真的很奇怪。加上闭包委托和元编程,事情可能与其他语言大不相同。 Gradle 混合了声明式配置和在 DSL 代码包装器中实现的命令式代码,因此“我正在配置这个”与“我正在编写代码来执行此操作”之间的界限肯定是模糊的。归根结底,它只是在运行代码,但这是从“这只是代码”的角度思考它的时代之一,会让你“哇!?”

configurations
块是一个ConfigurationContainer,容器是非常灵活的实体,其中的元素可以是任何你想要的。也许如果我们像这样重写它会不那么奇怪:

configurations {
   dev {
   }
   staging {
   }
   production {
   }
}

当有人写

myConfig
时没有括号,它与一个空的 Closure 块相同。这将意味着有效地接受默认值。 现在,我将 myConfig 替换为更熟悉、更具体的示例(开发、暂存、生产)。但是您可以想象我们可能希望使配置灵活,并且客户可以在这里定义适合他/她的环境的任何内容。另请注意,我在之后添加了空的 Closure 块以显示那些 Configurations 可以使用以下属性进一步配置:

configurations {
   dev {
      description = "Used for local development only."
   }
   staging {
      description = "Can be deployed to the staging environment only."
   }
   production {
      description = "The environment deployed to customer facing system."
   }
}

现在所有这些是如何在幕后实施的?好吧,一旦您理解了

delegate
属性在 groovy 闭包中的作用,它就非常简单了。如果你自己实现
ConfigurationContainer
你会做这样的事情(这是松散的想法伪代码):

public class ConfigurationContainer {

   Map<String,Config> configs = [:]

   def methodMissing(String name, def args) {
      configs[ name ] = new Config( name )
      Closure c = args.first()
      c.delegate = configs[ name ]
      c.call()
   }
}

class Config {
   boolean debug = false
}

现在,如果您查看 Groovy 代码(如果您想创建类似的东西,请参阅 NamedDomainObjectContainer),这并不是它的完成方式,但您可以这样想。

  1. 我正在使用元编程方法
    methodMissing
    来捕获用户声明的任何配置名称(即 dev、staging、production、aws、azure 等)。
  2. 创建一个
    Config
    对象,该对象可能包含此块想要配置的一些属性。
  3. 我正在抓住第一个参数(即期待一个闭包)
  4. delegate
    Closure
    设置为我的
    Config
    对象。
  5. 使用
    call()
  6. 调用闭包

现在,对该闭包中的属性或方法的任何调用都将delegate

delegate
属性上设置的实例。这就像在闭包中写
config.debug
而不需要说
config.
。闭包知道你的意思。

这意味着如果我们在 Gradle 中做这个假设的事情,我们的代码可能会变成:

configurations {
   dev {
      debug = true
   }
   staging {
      debug = true
   }
   production
}

因为我们的

Config
对象已经有默认的
debug = false
并且生产只需要声明,但不需要配置。

delegate
的概念是您尝试自己调用
Closure
时所缺少的。如果不设置
delegate
属性,
Closure
中的代码不知道如何找到这些属性并抛出
MisingPropertyException
.

© www.soinside.com 2019 - 2024. All rights reserved.