func biggerOne(_ a : Int, _ b : Int) -> Int? {
if a == b {
return nil
} else if a > b {
return a
} else {
return b
}
}
var someClosure : (Int, Int) -> Int? = biggerOne(_:_:)
// Not working
someClosure = { (left : Int, right : Int) in
someClosure(left , right)
}
print(someClosure(2,3)!)
// Working
someClosure = { [someClosure] (left : Int, right : Int) in
someClosure(left , right)
}
print(someClosure(2,3)!)
Я знал, что замыкание использует список захвата для хранения значений при создании, поэтому может решить проблему, но почему приведенный выше код не работает?
Если у вас есть какие-либо идеи, я был бы признателен за вашу помощь.
@matt Просто для учебы. Специальной цели нет..
Итак, вы намеренно формируете бесконечный цикл, а затем спрашиваете, почему он бесконечен?
Есть циклические ссылки, someClosure
звонит сам себе.
Попробуйте удалить циклические ссылки:
// Now it works
let firstClosure = { (left : Int, right : Int) in
someClosure(left , right)
}
print(firstClosure(2,3)!)
// Working
let secondClosure = { [someClosure] (left : Int, right : Int) in
someClosure(left , right)
}
print(secondClosure(2,3)!)
Без захвата someClosure
здесь просто вызывает себя, а затем вызывает переполнение стека:
someClosure = { (left : Int, right : Int) in
someClosure(left , right) // this call refers to the new value of "someClosure"
}
(Я не уверен, что тот факт, что это проходит компиляцию, является преднамеренным.)
Это похоже на то, как если бы вы определили именованную функцию, например:
func someClosure(left: Int, right: Int): Int? {
someClosure(left: left, right: right)
}
С другой стороны, список захвата фиксирует старое значение someClosure
, поэтому «someClosure
» внутри тела замыкания относится к захваченному значению (т. е. старому значению), и бесконечная рекурсия отсутствует. Вы можете думать об этом как:
let captured = someClosure
someClosure = { (left : Int, right : Int) in
captured(left , right)
}
Используя lldb yourExecutable
и команду thread backtrace
, вы можете увидеть множество дублированных кадров стека, вызванных рекурсией.
(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7ff7bf6ffff8)
* frame #0: 0x00007ff822e4fa99 libswiftCore.dylib`swift_beginAccess + 41
frame #1: 0x0000000100003d87 yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 71
frame #2: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #3: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #4: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
...
frame #65515: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #65516: 0x0000000100003dbc yourExecutable`$s14yourExecutableSiSgSi_SitcfU_ + 124
frame #65517: 0x0000000100003baa yourExecutable`main + 218
frame #65518: 0x00000001000154fe dyld`start + 462
Почему вы вообще сказали что-то из этого? Есть ли у этого кода вообще какая-то цель?