Почему этот код закрытия выдает ошибку, если не используется список захвата?

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 19.03.2022 11:49

@matt Просто для учебы. Специальной цели нет..

2nebin 19.03.2022 11:52

Итак, вы намеренно формируете бесконечный цикл, а затем спрашиваете, почему он бесконечен?

matt 19.03.2022 12:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
35
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Есть циклические ссылки, 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

Другие вопросы по теме