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

参考

相关推荐
sakiko_10 小时前
OC基础语法(与Swift对比)-1
开发语言·ios·objective-c·swift
2501_9160088919 小时前
Flutter 开发 iOS,项目打包成 IPA,命令与免 Xcode两种方法
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
东坡肘子2 天前
举手之劳 -- 肘子的 Swift 周报 #151
人工智能·swiftui·swift
sakiko_2 天前
Swift学习笔记42-SwiftUI的属性包装器(讲解+面试)
笔记·学习·ios·swiftui·swift
weixin_531670895 天前
Interlude起来:动作动画和文字通知哪个更适合休息提醒?Mac上有没有用桌宠做动作引导的软件?
人工智能·macos·mac·swift
Daniel_Coder5 天前
我用 SwiftUI + GRDB 做了一个「按时吃药·服药提醒」App
ios·swiftui·swift·widgetkit
末代iOS程序员华仔6 天前
iOS个人开发者账号申请为啥会被卡住
ios·swift·figma
denggun123457 天前
信号量(DispatchSemaphore vs AsyncSemaphore)、swift协作式线程池 and python信号量
开发语言·python·swift
2501_915918417 天前
Swift IDE 有哪些?按平台和需求选择Swift 开发工具
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
懋学的前端攻城狮8 天前
把 SwiftUI List 换成 NSTableView:一次目录树卡顿的排查记录
macos·swiftui·swift