我不确定这是不是一个错误,或者它确实是如何运作的?
class A {
init() throws { }
}
class B {
lazy var instance = A()
}
此代码使用XCode 9和最新Swift
版本编译时没有错误,并且除非Class A
init()
真正抛出,否则工作完美,然后lazy var为空指针。但不应该以某种方式编译这段代码吗?
答案 0 :(得分:5)
这确实是一个错误(SR-7862) - 你不能从属性初始化上下文中抛出错误(即使你可以,你也需要使用$checkboxesFound == 0
为调用添加前缀),因此编译器应该产生错误。
我已经打开了一个拉取请求来修复此问题(#17022)。
编辑:该修补程序现已被挑选到4.2分支,所以它将被修复为使用Xcode 10发布Swift 4.2(直到发布时你可以{{3 }})。
答案 1 :(得分:1)
作为对你问题的回答:
但不应该以某种方式编译这段代码吗?
好吧,在某些时候你的代码片段没有任何问题(因为 - 你提到过 - 类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()
你不会得到编译时错误,然而试图将它与实际投掷一起使用会导致运行时错误:
let myB = B()
print(myB.instance) // crash!
我建议解决此问题的方法是将instance
声明为lazy 可选变量:
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