从 Groovy 中的闭包修改脚本变量

2024-02-08

我正在尝试从函数的闭包内部修改脚本变量。这个问题可以归结为:

@groovy.transform.Field int myField = 0

incrementField()
assert myField == 1

def incrementField() {
    1.times { myField++ }
}

我认为这个问题与关闭代表 http://groovy-lang.org/closures.html#_delegation_strategy,但我无法完全理解这些文档。


这种行为是由于groovy.lang.Script http://docs.groovy-lang.org/latest/html/api/groovy/lang/Script.html类以及它重写以下方法的事实:

  • Object getProperty(String property) http://docs.groovy-lang.org/latest/html/api/groovy/lang/Script.html#getProperty-java.lang.String-
  • void setProperty(String property, Object newValue) https://github.com/apache/groovy/blob/master/src/main/groovy/lang/Script.java

您在示例中显示的闭包使用delegate设置为脚本对象,这就是当您尝试访问或修改脚本中定义的字段时执行两个重写方法的原因。

现在让我们看看当您的示例结束时会发生什么

{ myField++ }

首先,getProperty("myField")被调用以返回与该属性关联的值。该方法的实现如下:

public Object getProperty(String property) {
    try {
        return binding.getVariable(property);
    } catch (MissingPropertyException e) {
        return super.getProperty(property);
    }
}

Source: https://github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Script.java#L54 https://github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Script.java#L54

binding对象一开始只包含一个变量 - 闭包的args大批。如果我们看一下实施binding.getVariable(property)方法我们会看到:

public Object getVariable(String name) {
    if (variables == null)
        throw new MissingPropertyException(name, this.getClass());

    Object result = variables.get(name);

    if (result == null && !variables.containsKey(name)) {
        throw new MissingPropertyException(name, this.getClass());
    }

    return result;
}

Source: https://github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Binding.java#L56 https://github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Binding.java#L56

在我们的例子中MissingPropertyException正在被抛出,所以Script.getProperty(property)方法返回字段的值myField在我们的 Groovy 脚本中定义 -0。然后 Groovy 将此值增加 1 并尝试将此新值设置为字段myField。在这种情况下Script.setProperty(property, value)正在被调用:

public void setProperty(String property, Object newValue) {
    if ("binding".equals(property))
        setBinding((Binding) newValue);
    else if("metaClass".equals(property))
        setMetaClass((MetaClass)newValue);
    else
        binding.setVariable(property, newValue);
}

Source: https://github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Script.java#L62 https://github.com/apache/groovy/blob/GROOVY_2_4_X/src/main/groovy/lang/Script.java#L62

正如你所看到的,它使用以下命令设置了这个新值bindings目的。如果我们显示binding.variables我们将看到现在这个内部映射包含两个条目:args -> [:] and myField -> 1。它解释了为什么脚本中的断言总是失败。您定义的闭包主体永远不会到达myField脚本类中的字段。

解决方法

如果您对以下事实不满意Script类覆盖setProperty(property, value)方法,您始终可以在脚本中手动覆盖它并使用与GroovyObjectSupport.setProperty(property, value)。只需将以下方法添加到您的 Groovy 脚本中:

@Override
void setProperty(String property, Object newValue) {
    getMetaClass().setProperty(this, property, newValue)
}

现在闭包定义在incrementField将为类字段设置一个新值,而不是bindings目的。当然,它可能会导致一些奇怪的副作用,你必须意识到这一点。我希望它有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 Groovy 中的闭包修改脚本变量 的相关文章

  • 修改String字段的getter的返回值

    假设我的应用程序中有一些类似于域类的类 其中包含一些 Long Double Date 和 String 字段 这些类使用一些公共字段和一些公共方法扩展了基类 每当我访问 String 类字段 通过 getter 时 我想对返回的值进行一些
  • 如何在 WebStorm 中安装 Groovy 插件?

    我正在使用 WebStorm 进行开发 我想要为 Jenkins Groovy 管道提供语法突出显示 使用IntelliJ IDEA来编辑Jenkinsfile是可以的 但是在IDE之间来回切换显然很不方便 我可以安装吗Groovy 插件
  • Groovy 元编程 - 将静态方法添加到 Object.metaClass

    我遇到了无法解决的 Groovy 元编程问题 将静态方法 foo 添加到类 FooBar 时 FooBar foo 按预期工作 FooBar metaClass static foo println hello FooBar foo 但是
  • 反思 Groovy 脚本中声明的函数

    有没有一种方法可以获取 Groovy 脚本中声明的函数的反射数据 该脚本已通过GroovyShell目的 具体来说 我想枚举脚本中的函数并访问附加到它们的注释 Put this到 Groovy 脚本的最后一行 它将作为脚本的返回值 a la
  • Jenkins 多分支:更改 Groovy 的工作描述

    我在詹金斯的多分支项目工作正常 但我想修改job描述 默认情况下为 完整项目名称 xxxx 以更有意义 我可以使用以下命令轻松更改构建描述currentBuild当我的变量Jenkinfile已执行 但我不知道如何修改父作业描述 我的用例是
  • Groovy HttpBuilder - 获取失败响应的正文

    我正在尝试使用 Groovy HTTPBuilder 编写一个集成测试 该测试将验证正文中是否返回正确的错误消息以及 HTTP 409 状态消息 但是 我无法弄清楚如何在失败情况下实际访问 HTTP 响应的正文 http request E
  • 如何在不使用 -cp 开关的情况下在 Groovy 中自动加载数据库 jar?

    我想简化调用 Oracle 数据库的 Groovy 脚本的执行 如何将 ojdbc jar 添加到默认类路径以便我可以运行 groovy RunScript groovy 代替 groovy cp ojdbc5 jar RunScript
  • Grails/GGTS 2.4.2 没有将插件放在类路径上?

    我正在尝试将旧的 1 3 Grails 项目更新到最新的 Grails Groovy etc 所以我下载了 Grails 2 4 2 Groovy 2 3 和 Java 1 7 0 65 然后我通过 Import gt Grails 导入了
  • 如何生成源文件并用gradle编译

    我有一个类似于以下内容的 gradle 构建脚本 apply plugin war task genSources lt lt here I generate some java files making sure that source
  • 如何为新任务类型扩展 Gradle 任务的行为?

    我想为一些测试任务设置一些东西 更具体地说 我想添加一些环境变量和一些系统属性 也许还有一些其他内容 例如 依赖项 或 workingDir 与常规的Test任务我可以做到这一点 task test1 type Test dependsOn
  • 在 GORM 中重命名复合外键

    我有以下课程 class Catalog static mapping id composite name manufacturer columns name column cat name manufacturer column manu
  • SOAPUI 方括号括住我的实际结果,导致断言失败

    我正在编写一个 Groovy 脚本断言 该断言根据 SOAP 响应中包含的值来验证先前 JDBC 响应步骤中的值 当我运行脚本时 我可以看到两个值返回相同 但实际结果值 来自 SOAP 响应 被方括号括起来 这反过来又使断言失败 我猜这与一
  • 在 Grails 中应用 Groovy 扩展会产生 String#toBoolean() 的 MissingMethodException

    背景 Groovy 有以下特点向现有类添加方法 http docs codehaus org display GROOVY Creating an extension module 我发现some https github com timy
  • 从 XML 对象中获取值

    我正在尝试使用 java 获取 XML 对象的值 我的 XML 源
  • Grails:在域类中动态注入服务

    我需要注入基于域属性的服务 到目前为止我想出了以下内容 ApplicationHolder application getServiceClass package property Service clazz 但以这种方式加载它不会注入它的
  • Groovy:验证 JSON 字符串

    我需要检查 Groovy 中的字符串是否为有效的 JSON 我的第一个想法就是把它发送出去new JsonSlurper parseText myString 并且 如果没有例外 就假设它是正确的 然而 我发现 Groovy 很乐意接受尾随
  • Groovy 中的显式输入:有时还是从不?

    后来 仍然无法弄清楚 Groovy 是否具有静态类型 似乎没有 或者使用显式类型生成的字节码是否不同 似乎是 无论如何 回答这个问题 One of the main differences between Groovy and other
  • 如何从詹金斯管道获取所有参数(参数化构建)?

    我正在较新版本的 jenkins 中构建一个参数化管道作业 在较旧版本的 jenkins 中 我使用 getbinding getVariables 来检索所有参数 但较新的版本它返回空值 如何在新版本的詹金斯中检索参数 全部 您可以使用
  • 无法在 Intellij 上创建 Groove 脚本 - @NotNull 参数的参数

    我正在尝试开始学习 Groovy 以便在 JIRA 上使用 ScriptRunner 执行 API 调用 所以我从基础开始 我的问题是我什至无法使用 Intellij 创建 Groovy 脚本 在项目创建时它选择Groovy并选择项目SDK
  • 如何在启动时向 groovysh 添加导入?

    我正在开发一个项目 希望用户在 Groovysh 上试验 Java 类 我想让他们方便 并希望在 groovysh 启动时默认导入某些包 这样用户就不必在每次启动 shell 时重新输入相同的导入 有谁知道如何做到这一点 提前致谢 伊戈尔

随机推荐

  • 何时使用构建工具?

    一个初学者问题 请耐心等待 我只是想知道在什么情况下应该使用像 nant 或 msbuild 这样的构建工具 我正在开发一个中型应用程序 net 3 0 每个开发人员都在做他的工作并在他的机器上进行构建 检查他的代码更改到存储库中 全部完成
  • 对象未使用 JPA/JTA/JBOSS/CDI 持久化

    请帮助我理解为什么对象没有通过以下代码持久化 它抛出javax persistence TransactionRequiredException JBAS011469 需要事务来执行此操作 使用事务或扩展持久性上下文 public clas
  • 设置 3 个元素的高度,取最大值,跨多行

    我有一个 div 布局 全部向左浮动 列数为 3 这些层内部是长度不同的文本 因此层的高度不同 因此无法正确对齐 而且看起来也不太好 因为边框不身高匹配 我可以为所有 div 设置固定高度 但这会在某些行上留下巨大的空白 因此我编写了一些
  • Laravel:Redis 无法建立连接:[tcp://127.0.0.1:6379]

    我已经用 laravel 安装了 redis 添加了 predis predis 1 0 然后为了测试我添加了以下代码 public function showRedis id 1 user Redis get user profile i
  • Rails 4 和 Devise:Devise 不保存新信息(名字、姓氏、个人资料名称)

    我正在使用 Rails 4 和 Devise 我正在尝试在我的应用程序上发布的状态中显示用户的名字 我已经正确完成了我能想到的所有事情 添加用户模型后迁移数据库 并且数据库仍然没有保存我标题中列出的三个新字段 Devise 保存它附带的内容
  • kotlin,如何将 HashMap 放入 Parcelable 中

    在实现 Parcelable 的类中 它有一个 HashMap 成员 看到 Parcelable 有public final void readMap Map outVal ClassLoader loader 但找不到使用它的示例 如果通
  • 如何在不破坏皮肤的情况下向 MediaWiki 站点添加水平顶部菜单栏?

    我希望我的 MediaWiki 网站 除了侧边栏之外 或者代替侧边栏 在网站顶部有一个链接栏 在每个页面上都可见 要求 为了尽量减少以后的维护负担 我的要求是 无需修改核心 扩展或皮肤代码 我不想维护项目分支 理想情况下 特权用户应该能够通
  • WPF 可见性绑定到具有多个变量的布尔表达式

    我有两个布尔值 我想根据它们的值显示图像 如下所示
  • Java:将二进制字符串转换为十六进制字符串[重复]

    这个问题在这里已经有答案了 我需要将二进制字符串转换为十六进制字符串 但我有一个问题 我通过以下方法将二进制字符串转换为十六进制字符串 public static String binaryToHex String bin return L
  • Delphi - 按名称调用记录方法

    我为我的应用程序编写了一种脚本语言 我的目标是能够在脚本中发布来自 delphi 的任何类型 我使用 rtti 来自动执行此任务 对于任何实例类型 例如类 我使用以下代码从脚本查找并调用方法 var Info TRttiType Meth
  • WPF 用户控件数据绑定不起作用

    我正在创建一个简单的用户控件 将弹出窗口与文本视图相结合 这没什么疯狂的 当我首先在窗口中将其设置为全部样式时 它工作得很好 但是当我将其移到用户控件中以实际完成它时 它将不再正常工作 我将最小值和最大值传递给控件 然后它会自动创建一个数字
  • Highcharts 中分组柱形图的深入分析

    我正在尝试对高图中的分组柱形图进行深入分析 我的图表在这里 function Create the chart container highcharts chart type column title text Basic drilldow
  • 重叠指针、类型的限制限定符的粒度

    The 整点 of restrict是承诺通过一个指针的访问不会别名另一个 也就是说 有些例子中重叠的内存地址并不意味着别名 例如 int arr ptr0 arr 0 int arr ptr1 arr 1 for int i 0 i lt
  • 如何显示当前工作目录和上次提交的差异?

    我正在使用 git 并需要包含在差异结果未跟踪文件中 那么我必须执行什么命令才能获取当前工作目录和 HEAD 之间的所有差异 甚至部分差异存在于新文件添加中 Um git diff 毕竟 这就是它的作用 Update 不在暂存区域中的文件
  • 将 HTML 内容渲染到 Google 电子表格

    我的单元格 A1 中有一个 HTML 内容 我想渲染该 HTML 内容并将渲染的 HTML 内容添加到单元格 B1 中 例如如果我在 A1 中有这个 HTML
  • 反应上下文不更新

    我已经设置了一个使用 Context 来存储页面标题的基本示例项目 但是当我设置它时 组件不会重新呈现 主要文件 上下文 js import React from react const Context React createContex
  • React 上下文消费者如何访问消费组件的引用

    我使用以下方法构建了一个高阶组件React 的新上下文 API https reactjs org docs context html我正在尝试找到一种能够访问参考的方法 通过ref 包装的子组件 tl dr 本质上我想要转发裁判 http
  • Backbone.js 链接文件到模型

    我正在使用 django 和backbone js 创建一个Web 应用程序 问题是我需要将文件上传到服务器 如何将主干模型与文件链接 因此 当我执行 model save 时 文件会上传到服务器 编辑 只是为了让事情变得清楚 我想做的是将
  • 在 Flutter 中使用 JsonSerialized 时如何识别动态键?

    让我们假设 直到最近 我才听到下面的声音Json response AA product id 111 type C 而且 我写了下面的内容 model dart从 json 转换为对象 模型 dart JsonSerializable c
  • 从 Groovy 中的闭包修改脚本变量

    我正在尝试从函数的闭包内部修改脚本变量 这个问题可以归结为 groovy transform Field int myField 0 incrementField assert myField 1 def incrementField 1