Closure - осознать, понять и полюбить


#1

Добрый день, ребята поделитесь своим опытом, кто как изучал Closure? Что нужно сделать, чтобы получить ясное понимания алгоритма работы и использования Closure.


#2

Главное понимание - это функция! ))), выполняемая сразу после определения :slight_smile:


#3

Спасибо за ответ, вроде функции понимаю, но не совсе понятно как делается вход Closure.


#4

Больше практики и поймёте)


#5

Не страшно: все сначала не понимают и просто копи-пастят. Со временем и практикой всё придёт. Здесь в курсах где-то Иван довольно понятно объяснял.


#6

Все спасибо за ответы.
Я сам себе говорю что нужно время для понимания, но когда читаешь документацию по Closure начинается боль :sleepy:


#7

А в видео формате смотрели?


#8

Видео смотрел, некоторые моменты понятные некоторые нет. Пока очень сырое понимание, особенно трудно читать код.

Пример

func makeIncrementer() -> (Int) -> Int {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)

Как правильно читать этот код?

Так

Функция makeIncrementer котороя не чего напринимает, но возвращает функцию которая принимает Int и возвращает Int.

Правильно ли я прочитал код?


#9

Да правильно. Можно короче. Функция func makeIncrementer возвращает функцию func addOne.


#10

Спасибо за ответ.

Может поможете прочитать это:

var addClosure: (Int, Int) -> Int = { $0 + $1 }

func returnClosure() -> (Int, Int) -> Int {
return addClosure
}

returnClosure

returnClosure()(10, 20)

addClosure - это переменная с типом (Int, Int) -> Int которая принимает Closure?

returnClosure - это функция которая не чего не принимает, но возвращает Closure который который принимает переменную, которая принимает функцию?

Я немного запутался…


#11

Как я понимаю, closure это блок кода, который передается в качестве параметра в другую функцию, а не в качестве возвращаемого значения.

Функция calculatorFunc, принимает в качестве параметров 2 переменные типа Int, а также функцию для вычисления значений этих переменных.

Пример 1:

func sumFunc(a: Int, b: Int) -> Int { return a + b }

func subtractFunc(a: Int, b: Int) -> Int { return a - b }

func multiplyFunc(a: Int, b: Int) -> Int { return a * b }

func divideFunc(a: Int, b: Int) -> Int { return a / b }

func calculatorFunc(a: Int, b: Int, funcToCalculate: (Int, Int) -> Int) -> Int { return funcToCalculate(a, b) }


let sumResult = calculatorFunc(a: 1, b: 2, funcToCalculate: sumFunc)

let subtractResult = calculatorFunc(a: 1, b: 2, funcToCalculate: subtractFunc)

let divideResult = calculatorFunc(a: 10, b: 5, funcToCalculate: divideFunc)

let multiplyResult = calculatorFunc(a: 5, b: 5, funcToCalculate: multiplyFunc)

Важно обратить внимание на следующее:

Если написать calculatorFunc(a: 1, b: 2, funcToCalculate: sumFunc ()), то в парметр funcToCalculate: будет передана не ссылка на блок кода с именем sumFunc, а значение, возвращаемое этой функцией, что вызовет ошибку компиляции.

В примере 1 для вычисления значений были объявлены 4 функции, если в будущем понадобятся дополнительные операции вычисления, то придется создавать еще функции и еще и еще.

Пример 2. С замыканием:

func calculatorFuncVersion2(a: Int, b: Int, closure: (Int, Int)  ->  Int ) -> Int { return closure(a, b) }

let sumResultVer2 = calculatorFuncVersion2(a: 4, b: 5, closure: { (a, b) -> Int in return a + b })

let substractResultVer2 = calculatorFuncVersion2(a: 10, b: 3, closure: { (a, b) -> Int in return a - b })

let divideResultVer2 = calculatorFuncVersion2(a: 20, b: 10, closure: { (a, b) -> Int in return a / b})

let multiplyResultVer2 = calculatorFuncVersion2(a: 5, b: 5) { (a, b) -> Int in return a * b }

В примере 2, в качестве параметра closure: передается не ссылка на ранее объявленную функцию, передается сам блок кода, и в дальнейшем, если понадобиться добавить новые операции вычисления, достаточно написать эти вычисления в блоке кода замыкания без необходимости создавать для этого новые функции.


#12

Спасибо за разъяснения, крутой пример. Я с ним поработал немного и у меняя получилось еще сократить код.

Пример:

let multiplyResultVer2 = calculatorFuncVersion2(a: 5, b: 5) { $0 * $1 }


#13

сокращение кода хорошо, когда это уместно)
В моем примере важно понять сам смысл замыканий)


#14

Несовсем. Это безымянная функция. Например, вычисляемая переменная - это тоже клоужер.
При этом клоужер может передаваться в другую функцию, как вы указали. Тогда клоужер выполняется после завершения функции в которую он передан.


#15

Согласен. Получается функция может вернуть функцию и/или может вернуть блок кода в виде замыкания.


#16

Верно. В первом случае это просто возвращаемое значение. А если на вход подать безымянную функцию, то это и есть клоужер, который выполниться после основной функции.


#17

Вот тут я не совсем понял. Покажите пожалуйста на примере что значит подать замыкание на вход.


#18
func someFunc(closure: () -> ()) {
    //some main actions
    closure()
}

someFunc() {
    //some actions after main actions
}

#19

в этом примере замыкание передается в параметры функции, как и в моем примере.


#20

Я про это и говорил. Прошу простить, если выразился недостаточно понятно :slight_smile: