Lazy collections feature in Swift

深入理解代替单纯记忆

当前最新Swift版本为Swift 5.10

之前一直没注意过Lazy Collection这个Swift特性,最近在看Design protocol interfaces in Swift-WWDC时偶然看到,查阅了一下资料,发现这个特性很早就有了,早在WWDC2018时官方在Using Collections Effectively session中就提到了

先对该特性做一个概括性的描述:

  • 该特性是Sequence protocol的一个属性---var lazy: LazySequence<Self> { get }
  • 该属性返回的值同样描述了一个Sequence,虽然元素和原Sequence是相同的
  • 但对返回的Sequence进行各种高阶函数操作时(如map、reduce、filter等等),就拥有了lazy(延迟计算)能力
  • 所谓延迟计算的特性,可以理解为,直到真正需要用到集合中的元素时(而非在此之前的某个时机),才会真正去遍历或读取集合中的元素,且尽可能只读取所需要的元素,避免多余的读取操作

我把官方文档中对lazy属性的描述原文贴出来:

A sequence containing the same elements as this sequence, but on which some operations, such as map and filter, are implemented lazily.

我认为其实但看上面的内容是比较难描述lazy的能力,通过下面的两个例子可以更容易理解

Demo1

swift 复制代码
let array = [1, 2, 3]

let mappedArray = array.map({
    print("map on array --- \($0)")
    return $0
})


let lazyMappedArray = array.lazy.map({
    print("map on lazy array --- \($0)")
    return $0
})

print(lazyMappedArray.first)

控制台输出结果为

c 复制代码
map on array --- 1
map on array --- 2
map on array --- 3
map on lazy array --- 1
Optional(1)

以上例子得出的结论是:

  • 普通的集合,在没有lazy能力加持下,当执行到array.map时就会对集合所有元素进行遍历
  • 有了lazy能力加持后,array.lazy.map执行时,map中的closure完全不会执行
  • 直到执行到lazyMappedArray.first时,map的closure才会执行。而且并不会遍历整个array,仅对第一个元素执行了closure

Demo2

另一个场景是,有些时候我们需要声明一个Readonly的属性,返回一个集合,

  • 该集合的创建可能需要遍历一个已有的集合
  • 该Readonly的属性可能需要在程序整个生命周期中执行多次,每次使用都会执行上面的逻辑
swift 复制代码
struct ABC {
    let array = [1, 2, 3]
    var mappedArray: [Int] {
        return array.map {
            print("map on array --- \($0)")
            return $0
        }
    }
    
    var lazyMappedArray:  LazyMapSequence<LazySequence<[Int]>.Elements, LazySequence<[Int]>.Element> {
        return array.lazy.map({
            print("map on lazy array --- \($0)")
            return $0
        })
    }
}

let abc = ABC()
var mappedArray = abc.mappedArray
var lazyMappedArray = abc.lazyMappedArray
abc.mappedArray
abc.lazyMappedArray

lazyMappedArray.first
lazyMappedArray.first

控制台输出结果是

sql 复制代码
map on array --- 1
map on array --- 2
map on array --- 3
map on array --- 1
map on array --- 2
map on array --- 3

map on lazy array --- 1
map on lazy array --- 1
  • 每次执行abc.mappedArray,array都会被遍历一遍
  • 而abc.lazyMappedArray则不会去遍历array,因为还没有使用lazyMappedArray中的元素
  • lazyMappedArray.first尝试读取集合元素时,才会真正执行map closure逻辑

总结

  • Lazy collection特性是通过Sequence的lazy属性来提供给开发者使用,所以实现了Sequence协议的类型都支持lazy能力
  • 所谓延迟计算的特性,可以理解为,直到真正需要用到集合中的元素时(而非在此之前的某个时机),才会真正去遍历或读取集合中的元素,且尽可能只读取所需要的元素,避免多余的读取操作
  • lazy所赋予的延迟计算能力,在仅使用大数据量集合的部分元素、创建临时集合场景时,能显著降低额外性能损耗

参考

相关推荐
2501_9159184116 小时前
Windows 上开发 React Native iOS,真机调试、Fast Refresh 与打包 ipa
windows·vscode·react native·ios·个人开发·swift·敏捷流程
szp20051 天前
中文字幕烧进视频后整片空白:CoreText 低报行高,导出照样成功
ios·swift
2501_915106322 天前
iOS 单元测试怎么跑?用 KXApp 在 VS Code 里跑 XCTest 和 Swift Testing
ide·vscode·ios·单元测试·个人开发·swift·敏捷流程
东坡肘子2 天前
当应用不再属于特定操作系统 -- 肘子的 Swift 周报 #159
人工智能·swiftui·swift
2501_915106325 天前
Windows 用 KXBuild 开发 iOS 项目,CocoaPods、SPM 怎么处理?
windows·vscode·ios·个人开发·swift·敏捷流程·cocoapods
2501_916008896 天前
Windows 上写第一个 SwiftUI App,KXBuild 空工程起步,跑到 iPhone 真机
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
songgeb6 天前
iOS App支持设置RTL语言的实践
ios·swift·ui kit
2501_915106328 天前
KXApp 的 VS Code 真机调试:按下 Cmd+R 之后发生了什么
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2601_955518188 天前
36. 跨语言:C/C++与Swift&Objective-C混合编程(一)
objective-c·swift·c/c++·混合编程·跨语言
东坡肘子9 天前
谁是 AI-relay App 的真正威胁 -- 肘子的 Swift 周报 #158
人工智能·swiftui·swift