为了使groovy闭包修改委托范围中定义的变量,您是否需要显式指定delegate.theVariableName?

Chr*_*ord 8 groovy closures scope

我偶然发现Groovy关闭和代表的事情,我不确定是该语言的官方部分,甚至可能是一个错误.

基本上我定义了一个闭包,我将其作为来自外部源的字符串读入,并且类中定义闭包的变量之一需要由闭包修改.我写了一个简单的例子,展示了我发现的东西,什么不起作用.

如果查看下面的测试代码,您将看到一个定义变量的类

animal = "cat"
Run Code Online (Sandbox Code Playgroud)

和动态定义的两个闭包试图修改动物变量.

这工作>

String code = "{ ->   delegate.animal = 'bear';   return name + 'xx' ; }"
Run Code Online (Sandbox Code Playgroud)

但事实并非如此

String code = "{ ->   animal = 'bear';   return name + 'xx' ; }"
Run Code Online (Sandbox Code Playgroud)

看来我需要使用'delegate'明确限定我的待修改变量.为此工作.(我想我也可以在封闭类中定义一个setter,以便闭包调用以修改值.)

所以....我已经找到了如何使这项工作,但我有兴趣,如果有人可以指向我一些groovy doc解释其背后的规则.

具体来说....为什么简单的任务

animal = 'bear' 
Run Code Online (Sandbox Code Playgroud)

影响原始变量?是否有阴影副本在这里制作?

import org.junit.Test

/*
 * Author: cbedford
 * Date: 8/30/12
 * Time: 1:16 PM
 */

class GroovyTest {
    String animal = "cat"
    String name = "fred"

    @Test
    public void testDelegateWithModificationOfDelegateVariable() {
    String code = "{ ->   delegate.animal = 'bear';   return name + 'xx' ; }"
    def shell = new GroovyShell()
    def closure = shell.evaluate(code)

    closure.delegate = this
    def result = closure()

    println "result is $result"
    println "animal is $animal"

    assert animal == 'bear'
    assert result == 'fredxx'
    }


    // This test will FAIL.
    @Test
    public void testDelegateWithFailedModificationOfDelegateVariable() {
    String code = "{ ->   animal = 'bear';   return name + 'xx' ; }"
    def shell = new GroovyShell()
    def closure = shell.evaluate(code)

    closure.delegate = this
    def result = closure()

    println "result is $result"
    println "animal is $animal"

    assert animal == 'bear'
    assert result == 'fredxx'
    }
}
Run Code Online (Sandbox Code Playgroud)

ata*_*lor 8

Groovy闭包有五种解决闭包内符号的策略:

  • OWNER_FIRST:首先检查所有者(定义闭包的位置),然后检查委托
  • OWNER_ONLY:检查所有者,仅在明确引用时检查委托
  • DELEGATE_FIRST:首先检查委托,然后检查所有者
  • DELEGATE_ONLY:首先检查委托,仅在明确引用时检查所有者
  • TO_SELF:既不委托代表也不检查所有者

默认是OWNER_FIRST.由于闭包是动态定义的,因此您的所有者是一个Script对象,它本身具有特殊规则.编写animal = 'bear'一个脚本实际上会创建一个新的名为绑定animal并分配'bear'给它.

您可以通过简单地更改闭包上的解析策略,然后在调用它之前修复您的测试,而无需显式引用委托:

closure.resolveStrategy = Closure.DELEGATE_FIRST
Run Code Online (Sandbox Code Playgroud)

这将避免奇怪的脚本绑定并按预期使用委托.