Swift 斯威夫特的懒惰

Swift 斯威夫特的懒惰,swift,lazy-evaluation,swift2,Swift,Lazy Evaluation,Swift2,为什么这里使用了lazy extension SequenceType { func mapSome<U>(transform: Generator.Element -> U?) -> [U] { var result: [U] = [] for case let x? in lazy(self).map(transform) { result.append(x) } retu

为什么这里使用了
lazy

extension SequenceType {
    func mapSome<U>(transform: Generator.Element -> U?) -> [U] {
        var result: [U] = []
        for case let x? in lazy(self).map(transform) {
            result.append(x)
        }
        return result
    }
}
扩展序列类型{
func映射体(转换:Generator.Element->U?->[U]{
变量结果:[U]=[]
对于case,让x?在lazy(self).map(transform)中{
结果追加(x)
}
返回结果
}
}
此扩展接受一个转换函数,该函数返回一个可选值,并仅返回未转换为nil的值的数组


为什么不直接使用self.map(transform)?这里需要懒惰吗?

它避免了创建中间数组

self.map(transform)
返回包含转换结果的数组 所有序列元素,然后遍历这些元素以构建 具有非nil元素的结果数组

lazy(self).map(transform)
是转换元素的序列,然后 迭代以获取非nil元素。变换元素 在枚举过程中计算。(每次调用
next()
在延迟序列上,通过转换下一个元素来生成一个元素 原始序列的元素。)

两种方法都有效。惰性方法可能会执行得更好 对于大序列,但这取决于许多因素(大小 数组的类型,无论元素是值类型还是引用类型, 复制阵列元素等的成本有多高)。对于小型阵列 惰性方法可能会因为额外的 开销在一个具体的应用中,使用仪器进行剖面分析
帮助决定使用哪种方法。

正如Martin R提到的
lazy()
避免创建中间数组。但是,如果比较不同大小的数组上函数的执行时间,您会发现
lazy()
只“快”10%

有趣的是,您发现
lazy()
适用于少于200个元素的数组,其速度是不进行转换的函数的2倍,而包含更多元素的数组的速度几乎与该函数相同(快10%)

(使用Xcode 6.4和Xcode 7测试,在操场上使用全局函数和协议扩展作为(编译的)源文件)

所以
lazy()
更愿意用于
序列
,您不知道它是否是有限的。然后,for循环可能与
break
return
一起使用:

for element in lazy(sequence).map{ ... } {
    if element == 1000 {
        break
    }
    // use element
}

如果在无限
序列上调用map(如1,2,3…),执行也将是无限的。使用
lazy()
转换和执行会“延迟”,因此如果在最后一个元素之前打破循环,您可以更有效地处理“大”和无限序列。

顺便说一句,
flatMap(transform:Generator.element->U?->[U]
现在可以在Swift 2标准库中找到:)My(当然是非正式的)性能测试表明,惰性和非惰性对小型阵列的性能相同,但惰性确实在大型阵列上有一定优势,因此值得包括在内(特别是在这样的库函数中)。有趣的是,
flatMap
,从2.0开始执行相同的逻辑,它的性能比两者都差。@AirspeedVelocity:这很有趣,谢谢你的反馈。有趣的是,我得到了相反的结果!?见下面我的答案。