Что вызвало ошибку "Константа, захваченная замыканием перед инициализацией"

В следующем классе

class Foo {
   let _defaultValue = "N/A"
   let value: String 

   init (dict: NSDictionary) {
       self.value = dict["bar"] as? String! ?? _defaultValue
   }
}

компиляция завершается с сообщениемconstant 'self.value' captured by a closure before being initialized

Насколько я вижу, нет операторов читает self.value и это сообщение действительно сбивает с толку.

Обход, который я случайно изобрел, смущает меня еще больше:

class Foo {
       let value: String 

       init (dict: NSDictionary) {
           let _defaultValue = "N/A"
           self.value = dict["bar"] as? String! ?? _defaultValue
       }
    }

Изготовление _defaultValue объявленный и инициализированный внутри конструктор закрывает компилятор и программа работает!

Как объяснить такую ​​вещь?

1 ответ

Решение

Причиной сообщения об ошибке является то, что оператор слияния ноль определяется как

public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T

и выполняет "автоматическое замыкание" по второму аргументу (чтобы получить короткое замыкание). Так

self.value = dict["bar"] as? String ?? _defaultValue

преобразуется компилятором в

self.value = dict["bar"] as? String ?? { self._defaultValue }()

а вот компилятор жалуется потому что self захватывается до полной инициализации. (Сообщения об ошибках немного отличаются между Swift 2 и Swift 3).

Мне приходят на ум два обходных пути (возможно, у кого-то есть лучший): сначала вы можете назначить свойство локальной переменной:

init(dict: NSDictionary){
    let defValue = _defaultValue
    self.value = dict["bar"] as? String! ?? defValue
}

Или вы можете сделать это статическим свойством класса:

class Foo {
    static let _defaultValue = "N/A"
    let value: String

    init(dict: NSDictionary) {
        self.value = dict["bar"] as? String ?? Foo._defaultValue
    }
}
Другие вопросы по тегам