带闭包的惰性变量

时间:2015-10-14 00:45:05

标签: swift lazy-evaluation

在这个article中,它说(引用下面的代码):“你必须使用lazy来防止关闭被多次创建。”

private lazy var variable:SomeClass = {
    let fVariable = SomeClass()
    fVariable.value = 10
    return fVariable
}()

为什么懒惰会阻止多次创建闭包?为什么缺乏懒惰导致它不止一次评估?

2 个答案:

答案 0 :(得分:12)

您引用的教程代码是:

private lazy var variable:SomeClass = {
    let fVariable = SomeClass()
    fVariable.value = 10
    return fVariable
}()

与此对比:

private var variable:SomeClass {
    let fVariable = SomeClass()
    fVariable.value = 10
    return fVariable
}

第一个将variable初始化为新创建的SomeClass实例,最多一次(甚至可能不是那么多次)。第二个是只读计算变量,每次读取其值时都会创建一个新的SomeClass实例。

答案 1 :(得分:11)

你的直觉是正确的,那篇文章是不正确的。我猜测作者正在将计算属性语法与立即执行的闭包技巧混淆/混淆。 lazy关键字与执行闭包的次数无关。 lazy只会导致属性在第一次访问之前保持未初始化状态,此时将评估等号右侧的表达式。

为了简化,这个:

var myVar: MyType {
    return MyType()
}

与此非常不同:

var myVar: MyType = MyType()

在存储方面类似,但具有与此不同的初始化语义:

lazy var myVar: MyType = MyType()

在第一个示例中,myVar是计算属性,每次访问myVar时都会执行花括号内的代码。换句话说,每次访问myVar时,都会得到一个新创建的对象。

在第二个示例中,myVar是一个存储属性,在包含该属性的类或结构的初始化期间,等号后面的表达式被计算一次。

在第三个示例中,myVar仍然是一个存储属性,但是等号后面的表达式的评估(无论是初始化表达式,函数调用还是闭包调用)会被延迟,直到它被访问为止。

作为旁注,这行代码:

lazy var myVar: MyType = { ... }()

相当于:

func doStuffAndReturnMyType() { ... }
lazy var myVar: MyType = doStuffAndReturnMyType()

第一个例子中的简写并非专门为它设计 - 因为Swift的类型系统(很棒)并将闭包视为未命名(匿名)函数。