【问题标题】:Groovy closures - Missing propertyGroovy 闭包 - 缺少属性
【发布时间】:2019-07-07 19:56:34
【问题描述】:

在将 jenkins 管道编写为脚本之前,尝试学习 groovy 闭包。

以下代码:

def scores = [72,29,32,44,56]

def analyse(closure){
    closure(scores)
}

def firstScore(array){
    return array[0]
}

analyse(firstScore)

给出错误:

groovy.lang.MissingPropertyException: No such property: firstScore for class: groovy.lang.Binding
    at groovy.lang.Binding.getVariable(Binding.java:63)

如何解决这个错误?

【问题讨论】:

    标签: jenkins groovy closures


    【解决方案1】:

    您看到此错误是因为 firstScore 在您的代码示例中是一个方法而不是闭包。您可以将 firstScore 定义从方法更改为闭包,例如

    def firstScore = { array ->
        return array[0]
    }
    

    或者您可以使用 Groovy 的 method pointer operator 将方法转换为闭包。在这种情况下,您必须通过以下方式调用 analyze 方法:

    analyze(this.&firstScore)
    

    除此之外 - 您的 Groovy 脚本仍然会失败。您尝试在analyze 方法中访问scores。您需要知道脚本中定义的任何方法都会自动提升为类级别的方法(每个 Groovy 脚本都会编译为扩展 groovy.lang.Script 类的类)。您在 Groovy 脚本主体中定义的所有其他表达式和语句都是 Script.run() 方法的一部分,并且它们在本地范围内。所以当Script.analyze()方法被调用时,它会抱怨不存在的属性scores,因为scoresScript.run()方法的本地范围内。要修复它,您可以使用 @groovy.transform.Field 注释来注释 scores 变量,该注释将局部变量转换为类级别的属性 - 在这种情况下,scores 可以从任何方法访问。

    您可以在下面找到精选脚本的示例:

    import groovy.transform.Field
    
    @Field
    def scores = [72,29,32,44,56]
    
    def analyse(closure){
        closure(scores)
    }
    
    def firstScore(array){
        return array[0]
    }
    
    println analyse(this.&firstScore)
    

    输出:

    72
    

    最后但并非最不重要。仔细阅读"Best Practices for Scalable Pipeline Code" 博文。它解释了编写 Jenkins 管道代码的最佳实践。此外,您需要注意这样一个事实,即管道代码在 Groovy CPS 模式下执行,has a bunch of limitations。了解它们将帮助您解决从 Groovy 跳转到管道代码后肯定会遇到的问题。

    【讨论】:

    • 我们不能将方法作为参数传递吗?
    • 不,Groovy 不允许您将方法/函数作为参数传递。但是,您可以为此使用闭包,并且可以使用我在答案中解释的方法指针运算符将任何方法转换为闭包。当您在代码中调用closure(scores) 时,会隐式调用closure.call(scores),而call(args) 是存在于Closure 中的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多