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

vwhgwdsa  于 2023-03-18  发布在  其他
关注(0)|答案(2)|浏览(121)

阅读Gradle构建脚本时,我经常遇到以下代码

configurations {
  myConfig
}

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

def myClosure = { foo }
myClosure()

可预测地产生Caught: groovy.lang.MissingPropertyException: No such property: foo for class: Main

ddhy6vgd

ddhy6vgd1#

Groovy在省略括号时看起来非常奇怪。如果加入闭包委托和元编程,事情可能会与其他语言大不相同。Gradle混合了声明性配置和DSL代码 Package 器中实现的命令式代码,因此“我正在配置这个”与“我正在编写代码来完成这个”之间的界限肯定是模糊的。说到底,它只是运行代码,但这是其中一个时候,从“这一切都只是代码”的Angular 来思考它可以让你去“什么!?”
configurations块是一个ConfigurationContainer,容器是非常灵活的实体,其中的元素可以是任何你想要的,如果我们像这样重写它,可能会稍微不那么奇怪:

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

当有人写myConfig时不带括号,就相当于一个空的闭包块,这意味着实际上接受了默认值,现在,我用更熟悉更具体的例子替换了myConfig(开发、分段、但您可以想象,我们可能希望使配置更加灵活,客户可以在此定义任何适合其环境的内容。还请注意,我在后面添加了空的闭包块,以显示这些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等)。
1.创建一个Config对象,该对象可能包含此块要配置的一些属性。
1.我正在获取第一个参数(期望得到闭包)
1.将Closuredelegate设置为我的Config对象。
1.使用call()调用闭包
现在,任何对闭包中的属性或方法的调用都将委托delegate属性上的示例集,就像在闭包中写入config.debug而不需要说config.一样,闭包**知道 * 你的意思。
这意味着,如果我们在Gradle中执行此假设操作,代码可能会变为:

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

因为我们的Config对象已经有一个默认值debug = false,并且只需要声明生产,而不需要配置。
delegate的概念是您自己尝试调用Closure时所缺少的。如果不设置delegate属性,Closure中的代码就不知道如何找到这些属性并抛出MisingPropertyException

csbfibhn

csbfibhn2#

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

def map = [foo: "bar"]

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

这将打印bar
Groovy Web Console上试试
委托还可以实现methodMissing或propertyMissing以响应动态属性。

相关问题