从闭包访问局部变量

时间:2018-07-16 15:36:46

标签: gradle groovy closures

我正在尝试做这样的事情

Trees

有没有办法使这项工作有效?委托仅适用于类字段,不适用于本地变量。

2 个答案:

答案 0 :(得分:1)

当读取给定属性的值时,Groovy脚本会做一件事-当它存在于当前范围(局部变量,对象的字段等)中时,它将使用其值,否则将引用binding对象,包含不是变量,字段等的所有绑定。

您的情况如下:

myFunc {
  var1 = "hello"
  var2 = "world"
}

执行此闭包时,会将var1var2添加到具有相应值的binding中。 myFunc被执行时:

def myFunc(Closure config) {
  def var1
  def var2

  config()

  println var1
  println var2
}

它不使用binding来读取var1var2的值,因为在当前作用域中,两个变量都存在,因此

null
null

得到打印。

但是,如果您将var1之后的var2config()的阅读方式更改为这样的话:

def myFunc(Closure config) {
  def var1
  def var2

  config()

  println binding.getVariable("var1") ?: var1
  println binding.getVariable("var2") ?: var2
}

您将明确检查config()是否在var1上添加了var2binding,如果是,您将读取由执行的闭包修改的值。否则,您将读取var1var2的本地默认值。

hello
world

这类似于从myFunc中删除局部变量并调用如下闭合符:

def myFunc(Closure config) {
  config()

  println var1
  println var2
}

但是在这种情况下,您仅指的是binding,并且没有地方让局部变量参与该过程。我猜想您必须处理现有的局部变量,而不能仅仅删除它们-在这种情况下,明确地读取binding或局部变量是处理它的最佳方法。

毕业案例

如果在build.gradle脚本中遇到这种情况,则可以使用一种流行的方法,即使用地图对象委托,因此在闭包内部使用的所有变量都将自动分配为地图属性。考虑以下示例:

def myFunc(Closure config) {
  def var1
  def var2

  def map = [:]
  config.delegate = map
  config.resolveStrategy = Closure.DELEGATE_FIRST
  config()

  println map.getOrDefault('var1', var1)
  println map.getOrDefault('var2', var2)
}

task hello {
  doLast {
    myFunc {
      var1 = "hello"
      var2 = "world"
    }
  }
}

在这种情况下,以给定的闭包方式运行myFunc的结果是在委托的映射对象上分配var1var2属性。它使我们有机会使用map.getOrDefault(key,default)方法来检索带有闭包的值集或使用默认的局部变量值。

答案 1 :(得分:0)

您是否尝试过如下所示删除变量?

def myFunc(Closure config) {  
  config()    
  println var1
  println var2
}

myFunc {   
  var1 = "hello"   
  var2 = "world" 
}