@Lazy
和 lazy
是两个不同的概念。它们的区别主要在于它们的用途和功能:
1. lazy
(Swift 自带关键字)
-
描述:
lazy
是 Swift 的内置关键字,用于延迟初始化属性。使用lazy
修饰的属性只有在第一次被访问时才会计算和初始化。 -
使用场景: 适用于需要延迟初始化某些属性的情况,特别是那些初始化开销较大的对象或计算。
-
特性:
- 只能用于 变量 (
var
),因为延迟属性在第一次访问后可能会被修改。 - 属性的值在第一次访问时计算并存储下来,之后每次访问都返回已经计算好的值,不会重新计算。
- 适用于对象实例的属性,不能用于全局变量或常量。
- 只能用于 变量 (
-
例子:
struct MyStruct {
lazy var expensiveValue: Int = {
print("Computing expensive value")
return 42
}()
}
var example = MyStruct()
print(example.expensiveValue) // 第一次访问时计算并输出 "Computing expensive value" 和 42
print(example.expensiveValue) // 之后访问直接返回 42,不会再次计算
2. @Lazy
(Swift 5.5 引入的属性包装器)
-
描述:
@Lazy
是一个自定义的属性包装器(通过 Swift 5.5 的新特性属性包装器实现)。与lazy
类似,它用于延迟计算属性,但它可以在更广泛的上下文中使用,比如在结构体中使用不可变属性时。 -
使用场景: 适用于延迟计算更复杂的场景,比如需要控制如何计算或通过包装器实现更灵活的延迟机制。
@Lazy
可以应用于更复杂的类型和计算逻辑场景,具有更高的灵活性。 -
特性:
- 与
lazy
相比,@Lazy
可以用于任何类型的属性(包括let
),并且可以自定义延迟的行为。 @Lazy
包装器允许更灵活的实现方式,可以控制属性的计算和存储细节。- 可以自定义
wrappedValue
以及如何重置或再次计算属性。
- 与
-
例子:
@propertyWrapper
struct Lazy<Value> {
private var storage: Value?
private let initializer: () -> Value
init(wrappedValue: @autoclosure @escaping () -> Value) {
self.initializer = wrappedValue
}
var wrappedValue: Value {
mutating get {
if let value = storage {
return value
}
let value = initializer()
storage = value
return value
}
}
}
struct Example {
@Lazy var expensiveComputation: Int = {
print("Computing expensive value")
return 42
}()
}
var example = Example()
print(example.expensiveComputation) // 第一次访问时计算并输出 "Computing expensive value" 和 42
print(example.expensiveComputation) // 之后访问直接返回 42,不会再次计算
主要区别总结:
lazy
是 Swift 内置的关键字,主要用于延迟初始化存储属性,适用于简单场景。@Lazy
是基于 Swift 属性包装器实现的,提供了更灵活的方式来延迟计算属性,可以应用于更复杂的场景,且可以对let
和其他更复杂的行为进行包装。
如果只需要简单的延迟加载,lazy
就足够了;如果需要自定义的延迟行为,@Lazy
提供了更多的灵活性。