懒惰的 Var 与 Let
Lazy Var vs Let
我想对 Swift 中的某些属性使用延迟初始化。
我当前的代码如下所示:
lazy var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
事实是,一旦设置了字体大小,它就永远不会改变。
所以我想做这样的事情:
lazy let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
这是不可能的。
只有这个有效:
let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
所以 - 我想要一个 属性 将被延迟加载但永远不会改变。
正确的方法是什么?使用 let
并忘记惰性初始化?或者我应该使用 lazy var
而忘记 属性 的常数性质?
Swift 书 has the following note:
You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.
这在实现语言的上下文中是有意义的,因为所有常量存储属性都是在对象初始化完成之前计算的。这并不意味着 let
与 lazy
一起使用时可以更改语义,但尚未完成,因此 var
仍然是与 [=12] 的唯一选项=] 此时。
至于你提出的两个选择,我会根据效率在它们之间做出决定:
- 如果很少访问 属性 的值,并且前期计算成本很高,我会使用
var lazy
- 如果该值在超过 20..30% 的情况下被访问或者计算成本相对较低,我会使用
let
注意:我会进一步优化您的代码以将条件推入 CGFloat
初始值设定项:
let fontSize : CGFloat = CGFloat(someCase ? 30 : 17)
这是来自 Xcode 6.3 Beta / Swift 1.2 release notes 的最新经文:
let constants have been generalized to no longer require immediate
initialization. The new rule is that a let constant must be
initialized before use (like a var), and that it may only be
initialized: not reassigned or mutated after initialization.
This enables patterns like:
let x: SomeThing
if condition {
x = foo()
} else {
x = bar()
}
use(x)
which formerly required the use of a var, even though there is no
mutation taking place. (16181314)
显然你不是唯一对此感到沮丧的人。
正如 dasblinkenlight 指出的那样,在 Swift 中应始终将惰性属性声明为变量。然而,有可能使 属性 read-only 因此它只能从定义实体的源文件中进行变异。这是我能定义的最接近 "lazy let" 的地方。
private(set) lazy var fontSize: CGFloat = {
if someCase {
return 30
} else {
return 17
}
}()
您可以将 Burritos 用于惰性常量属性。该库为 Swift 5.1 提供了不同的 属性 包装器。通过将以下行添加到 Podfile 来使用 CocoaPods 安装它:
pod 'Burritos'
用这个库你可以替换
lazy var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
和
@LazyConstant var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
然后self.fontSize = 20
导致编译错误
我想对 Swift 中的某些属性使用延迟初始化。 我当前的代码如下所示:
lazy var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
事实是,一旦设置了字体大小,它就永远不会改变。 所以我想做这样的事情:
lazy let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
这是不可能的。
只有这个有效:
let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
所以 - 我想要一个 属性 将被延迟加载但永远不会改变。
正确的方法是什么?使用 let
并忘记惰性初始化?或者我应该使用 lazy var
而忘记 属性 的常数性质?
Swift 书 has the following note:
You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.
这在实现语言的上下文中是有意义的,因为所有常量存储属性都是在对象初始化完成之前计算的。这并不意味着 let
与 lazy
一起使用时可以更改语义,但尚未完成,因此 var
仍然是与 [=12] 的唯一选项=] 此时。
至于你提出的两个选择,我会根据效率在它们之间做出决定:
- 如果很少访问 属性 的值,并且前期计算成本很高,我会使用
var lazy
- 如果该值在超过 20..30% 的情况下被访问或者计算成本相对较低,我会使用
let
注意:我会进一步优化您的代码以将条件推入 CGFloat
初始值设定项:
let fontSize : CGFloat = CGFloat(someCase ? 30 : 17)
这是来自 Xcode 6.3 Beta / Swift 1.2 release notes 的最新经文:
let constants have been generalized to no longer require immediate initialization. The new rule is that a let constant must be initialized before use (like a var), and that it may only be initialized: not reassigned or mutated after initialization.
This enables patterns like:
let x: SomeThing
if condition {
x = foo()
} else {
x = bar()
}
use(x)
which formerly required the use of a var, even though there is no mutation taking place. (16181314)
显然你不是唯一对此感到沮丧的人。
正如 dasblinkenlight 指出的那样,在 Swift 中应始终将惰性属性声明为变量。然而,有可能使 属性 read-only 因此它只能从定义实体的源文件中进行变异。这是我能定义的最接近 "lazy let" 的地方。
private(set) lazy var fontSize: CGFloat = {
if someCase {
return 30
} else {
return 17
}
}()
您可以将 Burritos 用于惰性常量属性。该库为 Swift 5.1 提供了不同的 属性 包装器。通过将以下行添加到 Podfile 来使用 CocoaPods 安装它:
pod 'Burritos'
用这个库你可以替换
lazy var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
和
@LazyConstant var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
然后self.fontSize = 20
导致编译错误