Передайте замыкание (без запятой или паренов) в качестве последнего параметра функции в Groovy - PullRequest
0 голосов
/ 29 июня 2018

Как я могу вызвать функцию label и установить закрытие для нее как последний параметр таким образом? Этот код работает, только если я звоню label с круглыми скобками, но они мне не нужны. Можно ли установить замыкание в работу без них?

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

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

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

1 Ответ

0 голосов
/ 29 июня 2018

Если вы не хотите использовать скобки, вам нужно разделить аргументы замыкания на ,, чтобы сообщить компилятору, что вы хотите выполнить 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, которая принимает один параметр - closure. Реализация этих функций может выглядеть следующим образом:

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. Вы могли бы реализовать функцию methodMissing(name, args) Groovy, которая вызывается всякий раз, когда вызывается несуществующий метод. Рассмотрим следующий пример:

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'

Однако это не значит, что вы можете думать об этом как об эквивалентном избавлении от разделителя комы или скобок из вашего кода . Это пример простого DSL, написанного на Groovy, который использует механизм methodMissing для удовлетворения вызова несуществующих методов. Этот последний пример фактически такой же, как:

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

Функция, которая ожидает один аргумент, и в этом случае мы предоставляем его в результате test вызова метода с одним параметром { println "nothing" }.

Я бы настоятельно рекомендовал принять тот факт, что Groovy требует от вас разделять аргументы функции с помощью комы и не использовать такие DSL для удаления комы или скобок из кода. Groovy DSL очень мощный, и вы должны знать, что вы делаете, когда решите использовать этот инструмент в своем коде. Например, подумайте, что произойдет, если вы позвоните:

label "test" { println "something" }

и по какой-то причине метод, определенный как следующее закрытие:

def test = { int num -> num + 2 }

существует в вашем классе. Вы начнете получать исключения, потому что methodMissing больше не вызывается в этом случае. Метод test существует, но у него нет подписи, которая принимает одно замыкание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...