Как ответ на ваш вопрос:
Но не должен ли этот код каким-то образом не быть скомпилирован?
Ну, в какой-то момент ваш фрагмент кода работал безлюбая проблема (потому что, как вы упомянули, класс A
init фактически не генерирует), поэтому он может быть скомпилирован без каких-либо проблем.Чтобы сделать это более понятным, рассмотрим случай, подобный следующему:
let myString: String? = nil
print(myString!) // crashes!
он будет скомпилирован просто отлично!хотя мы все знаем, что он вылетает при оценке myString!
, то есть мы знаем, что он вызывает время выполнения сбой, но это не означает, что компилятор должен предотвращатьэто потому, что он может быть действительным в некоторый момент (например, если мы объявим его как let myString: String? = "Hello"
);Как и в вашем случае, он может быть действительным в некоторый момент - как упоминалось выше -.
Обычно для таких случаев мы, как разработчики, несем ответственность за его обработку в зависимости от желаемого поведения.
Обращаясь к этому случаю, мы могли бы спросить:
"Как мы можем реализовать переменную instance
lazy, чтобы перехватить ошибку (с блоком do-catch
)?"
На самом деле, этот код не будет компилироваться:
class B {
lazy var instance:A = {
do {
let myA = try A()
return myA
} catch {
print(error)
}
}()
}
с жалобой на то, что:
Отсутствует возврат в закрытии, ожидаемом длявернуть 'A'
, поскольку очевидно, что достижение блока catch означает, что возвращать нечего.Кроме того, как вы упомянули, даже если вы реализовали его как
lazy var instance = A()
, вы не получите ошибку времени компиляции, однако * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1045* попытка использования с фактическим броском должна привести ко времени выполненияошибка:
let myB = B()
print(myB.instance) // crash!
Что бы я предложил для решения этой проблемы, это объявить instance
как ленивый необязательный переменная:
class B {
lazy var instance:A? = {
do {
let myA = try A()
return myA
} catch {
print(error)
}
return nil
}()
}
На этом этапе, еслимы предполагаем, что A
инициализатор всегда выдает, пытаясь получить к нему доступ:
let myB = B()
print(myB.instance)
должен регистрировать:
пойманная ошибка
ноль
без сбоев.В противном случае он должен работать нормально, например:
let myB = B()
myB.instance?.doSomething() // works fine