Самым простым объяснением замыкания в Groovy является то, что оно является анонимной функцией.
1
2
|
def closure = { println "I am a closure" } closure() // Prints I am a closure |
Итак, первое, что нужно сказать, это то, что закрытие не печатается, когда закрытие определено, а только когда оно вызывается Закрытия облегчают отложенное выполнение. Также возможно передать параметры в замыкание
1
2
|
def closureWithParameters = {x, y -> print(x + " and " + y)} closureWithParameters( "Hello dudes" , "Hello Mega Dude" ) // Prints Hello dudes and Hello Mega Dude |
Когда замыкание имеет только один параметр, нам даже не нужен ->, мы можем просто использовать неявную переменную it .
1
2
|
def closureWithParameters = { println it } closureWithParameter( "Hello dude" ) // Prints Hello dude |
Сейчас, сейчас, сейчас детишки. Замыкания существуют не только в Groovy, они существуют во многих языках, и одна из их особенностей, о которых люди иногда забывают, состоит в том, что они содержат представление лексической среды функции. В английском это означает, что они получают снимок контекста, в котором они определены, и только они могут получить доступ к этому снимку и изменить его. В JavaScript мы можем сделать что-то вроде этого:
1
2
3
4
5
6
7
|
function outerFuntion () { var counter = 1 ; function innerFunction() { alert( "Counter=" + counter++); } return innerFunction; } |
Несмотря на то, что счетчик определен в externalFunction () как локальная переменная, он считается находящимся в лексической среде innerFunction (), поэтому он может получить к нему доступ. Когда innerFunction () возвращается в качестве замыкания, он получает свое собственное значение, к которому имеет доступ только он. Так что, если мы должны были сделать это:
1
2
|
var myClosure = outerFuntion(); // myFunc is now a pointer to the innerFunction closure. myClosure(); // Executes Counter=1; |
Сначала выполняется externalFunction (), и он возвращает замыкание innerFunction. Переменная присваивается этому закрытию. Теперь, сейчас, сейчас, обратите внимание, что ключевое слово здесь «вернулся». innerFunction () возвращается , он не выполняется. Итак, снова мы видим задержку исполнения, характерную для замыканий. Каждый раз, когда мы выполняем замыкание, счетчик увеличивается.
1
2
3
4
5
|
myClosure(); // Executes Counter=2; myClosure(); // Executes Counter=3; myClosure(); // Executes Counter=4; myClosure(); // Executes Counter=5; myClosure(); // Executes Counter=6; |
Таким образом, закрытие имеет состояние, которое оно запоминает через вызовы. Это состояние начинается как моментальный снимок контекста, в котором определена функция, и это то, что могут изменить только их закрытие. Так что да, это ключевой момент закрытия. Это особый вид объекта, который объединяет две вещи: функцию и среду, в которой эта функция была создана. Среда состоит из переменных, которые находились в области действия во время создания замыкания. Итак, вернемся к Groovy. Тот же пример будет выглядеть так:
1
2
3
4
5
6
|
def outerFunction () { def counter = 1 ; return { print "Counter=" + counter++ } } |
1
2
3
4
5
6
7
8
|
def myClosure = outerFunction() myClosure(); // executes 1 myClosure(); // executes 2 myClosure(); // executes 3 myClosure(); // executes 4 myClosure(); // executes 5 myClosure(); // executes 6 |
Это очень похоже на пример JavaScript. Слово def используется вместо функции . Мы также просто используем тот факт, что вам не нужно использовать функцию слова в Groovy, когда вы хотите определить анонимную функцию. Если бы мы хотели сделать внутреннюю функцию анонимной в версии JavaScript, мы могли бы сделать:
01
02
03
04
05
06
07
08
09
10
|
function outerFuntion () { var counter = 1 ; return function () { alert( "Counter=" + counter++); }; } var myClosure = outerFuntion(); // myFunc is now a pointer to the innerFunction closure. myClosure(); // Executes Counter=1; myClosure(); // Executes Counter=2; |
Но все равно придется использовать слово function, нам просто не нужно давать ему имя. Хорошо, так что до следующего раза береги себя.