8

我偶然发现了一些带有 Groovy 闭包和委托的东西,我不确定它们是否是该语言的官方部分,甚至可能是一个错误。

基本上,我定义了一个闭包,我从外部源作为字符串读入,并且类中定义闭包的变量之一需要由闭包修改。我写了一个简单的例子,展示了我发现什么是有效的,什么是无效的。

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

animal = "cat"

以及从试图修改动物变量的字符串中动态定义的两个闭包。

这有效>

String code = "{ ->   delegate.animal = 'bear';   return name + 'xx' ; }"

但这并不

String code = "{ ->   animal = 'bear';   return name + 'xx' ; }"

似乎我需要用“委托”明确限定我的待修改变量。为此工作。(我想我也可以在封闭类中定义一个 setter 来调用闭包来修改值。)

所以....我已经找到了如何进行这项工作,但如果有人能指出我一些解释其背后规则的常规文档,我会很感兴趣。

具体....为什么会简单的赋值

animal = 'bear' 

影响原始变量?这里有影本吗?

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'
    }
}
4

1 回答 1

9

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

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

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

您可以在不显式引用委托的情况下修复您的测试,只需在调用之前更改闭包上的解析策略:

closure.resolveStrategy = Closure.DELEGATE_FIRST

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

于 2012-08-30T20:51:50.243 回答