结构体中的 Lazy 属性探究
Swift 中的 lazy 关键字允许你定义这么一个属性:它的初始值在当它被首次访问的时候才计算。举个例子,试想通过一个结构体来描述一副图像。该图像的元数据(metadata)字典创建操作所需要的开销代价也许很大,因此我们更倾向于推迟这个行为直至需要该数据的时候。我们可以像这样声明一个 struct Image { lazy var metadata: [String:AnyObject] = { // 加载图片和解析 metadata,相当占内存 // ... return ... }() } 注意我们必须使用 访问 let image = Image() print(image.metadata) // error: Cannot use mutating getter on immutable value: 'image' is a 'let' constant. 你可以强制要求用户使用 使用Box包装类型另外一种选择是将 首先我们定义一个枚举类型,命名为 private enum LazyValue<T> { case NotYetComputed(() -> T) case Computed(T) } 现在我们将封装该枚举到一个类中,命名为 final class LazyBox<T> { init(computation: () -> T) { _value = .NotYetComputed(computation) } private var _value: LazyValue<T> var value: T { switch self._value { case .NotYetComputed(let computation): let result = computation() self._value = .Computed(result) return result case .Computed(let result): return result } } }
我们可以像这样使用 var counter = 0 let box = LazyBox<Int> { counter += 1; return counter * 10 } assert(box.value == 10) assert(box.value == 10) assert(counter == 1)// 倘若你把 1 改成 2,就会报错 上面这种方式的优势在于它能够应用到常量结构体中。而在其他方面,它相比较 struct Image { // 延迟存储 private let _metadata = LazyBox<[String:AnyObject]> { // 加载图片和解析 metadata,相当占内存 // ... return ... } var metadata: [String:AnyObject] { return _metadata.value } } let image = Image() print(image.metadata) // 不报错 这样该结构体依旧保留了它的值语义。值类型内部使用引用类型是惯用伎俩,以这种方式实现能够保证值语义。标准库中许多集合类型都是以这种方式实现的。 并发性这种实现方式还存在最后一个潜在问题,也就是未考虑并发性。倘若 我们可以将内部 final class LazyBox<T> { init(computation: () -> T) { _value = .NotYetComputed(computation) } private var _value: LazyValue<T> /// 所有对于 `_value` 的读写都在这个线程队列中。 private let queue = dispatch_queue_create( "LazyBox._value",DISPATCH_QUEUE_SERIAL) var value: T { var returnValue: T? = nil dispatch_sync(queue) { switch self._value { case .NotYetComputed(let computation): let result = computation() self._value = .Computed(result) returnValue = result case .Computed(let result): returnValue = result } } assert(returnValue != nil) return returnValue! } } 使用这种方式的缺点是每次访问 值得注意的是 Swift 并没有为
最新更新:就在我发布该文章之后的一个小时,Joe Groff 在 Swift evolution 中为属性行为发布了一个影响深远的提议,邮件内容请点击这里,一旦被采纳,将实现我在本文中讨论的内容(且远远不止),并以一个更自然的方式来实现。我强烈建议你看一下。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |