为了让 groovy 闭包修改在委托范围内定义的变量,是不是需要显式指定 delegate.theVariableName?

Posted

技术标签:

【中文标题】为了让 groovy 闭包修改在委托范围内定义的变量,是不是需要显式指定 delegate.theVariableName?【英文标题】:In order for a groovy closure to modify a variable defined in the scope of a delegate, do you need to explicitly specify delegate.theVariableName?为了让 groovy 闭包修改在委托范围内定义的变量,是否需要显式指定 delegate.theVariableName? 【发布时间】:2012-08-25 15:56:44 【问题描述】:

我偶然发现了一些带有 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'
    

【问题讨论】:

【参考方案1】:

Groovy 闭包有 five strategies 用于解析闭包内的符号:

OWNER_FIRST:首先检查所有者(定义闭包的地方),然后检查委托 OWNER_ONLY:检查所有者,仅在明确引用时检查委托 DELEGATE_FIRST:先检查delegate,再检查owner DELEGATE_ONLY:首先检查委托,仅在明确引用时检查所有者 TO_SELF:委托和所有者都没有被检查

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

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

closure.resolveStrategy = Closure.DELEGATE_FIRST

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

【讨论】:

以上是关于为了让 groovy 闭包修改在委托范围内定义的变量,是不是需要显式指定 delegate.theVariableName?的主要内容,如果未能解决你的问题,请参考以下文章

Javascript命名空间 - 如何根据命名导出函数范围内定义的函数和变量?

lua学习之闭包实现原理

排除 Grails 构建范围依赖项

深入理解Lua的闭包一:概念应用和实现原理

11-Groovy-Closures(闭包)和Ranges(范围)

深入理解Lua的闭包:概念和应用