@lazy 和 lazy 的区别

31 阅读2分钟

@Lazylazy 是两个不同的概念。它们的区别主要在于它们的用途和功能:

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 提供了更多的灵活性。