在Groovy中将闭包(不带逗号或括号)作为函数的最后一个参数传递

时间:2018-06-29 16:06:01

标签: groovy

如何通过这种方式调用label函数并将其闭包设置为最后一个参数?仅当我用括号调用label但不需要时,此代码才有效。是否可以在没有它们的情况下将闭包设为功能?

label = { name, callback ->
    callback()
}

label "lbl" {    // not works
    println "call $it"
}

label ("lbl") {  // works
    println "call $it"
}

1 个答案:

答案 0 :(得分:2)

如果不想使用括号,则必须用,分割闭包参数,以告诉编译器您要使用以下两个参数执行label

label "lbl", {    
    println "call $it"
}

此表示法等效于:

label("lbl", {    
    println "call $it"
})

Groovy具有这种语法糖,当闭包是函数原型的最后一个参数时,允许您在括号外传递闭包,这就是以下表示法起作用的原因:

label ("lbl") {
    println "call $it"
} 

但是它仍然与前面提到的等效。

  

如何使label "lbl" { }成为有效的语句?

     

如果您真的想编译如下代码:

label "lbl" {    
    println "call $it"
}
     

您需要注意一件事-这种表示法等同于:

label("lbl" {    
    println "call $it"
})
     

这意味着有一个函数label接受单个参数-从lbl函数返回的值接受一个参数-闭包。这些功能的实现可能如下所示:

def label = { value ->
  // do something with value
  println "The value accepted by label function is '${value}'"
}

def lbl = { callback ->
  callback?.call()
}

label "lbl" {
  println "call $it"
}
     

它会编译并将以下输出打印到控制台:

call null
The value accepted by label function is 'null'
     

当然,如您所见,您必须实现方法lbl,并且在大多数情况下,这是非常有限的-您不能使用与label不同的任何参数来调用lbl函数。您可以实现Groovy的methodMissing(name, args)函数,该函数在调用不存在的方法时被调用。考虑以下示例:

def methodMissing(String name, args) {

  if (args.length == 1 && args[0] instanceof Closure) {
    println "Running missing method '${name}'"
    return args[0].call()
  }

  throw new MissingMethodException(name, this.class, args)
}

def label = { value ->
  // do something with value
  println "The value accepted by label function is '${value}'"
}

def lbl = { callback ->
  callback?.call()
}

label "lbl" {
  println "call $it"
}

label "test" {
  println "nothing"
}
     

在这种情况下,当调用label "test" { println "nothing" }时,Groovy使用missingMethod,因为方法test在运行时上下文中不存在。

call null
The value accepted by label function is 'null'
Running missing method 'test'
nothing
The value accepted by label function is 'null'
     

但是这并不意味着您可以将其视为摆脱代码中的逗号分隔符或括号的原因。这是用Groovy编写的简单DSL的示例,该DSL使用methodMissing机制来满足不存在的方法调用。最后一个示例实际上与以下示例相同:

label("test" {
  println "nothing"
})
     

需要一个参数的函数,在这种情况下,我们通过使用单个参数test的{​​{1}}方法调用来提供该函数。

     

我强烈建议您接受这样的事实,即Groovy要求您用逗号分隔函数参数,并且不要使用此类DSL从代码中除去逗号或括号。 Groovy DSL非常强大,当您决定在代码中使用此工具时,您必须知道自己在做什么。例如,考虑一下如果您拨打电话会发生什么:

{ println "nothing" }
     

以及出于某种原因定义为以下闭包的方法:

label "test" { println "something" }
     

存在于您的班级中。您将开始获取异常,因为在这种情况下不再调用def test = { int num -> num + 2 } 。方法methodMissing存在,但是它没有接受单个闭包的签名。