斯威夫特的懒惰

iel*_*ani 8 lazy-evaluation swift 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)
        }
        return result
    }
}
Run Code Online (Sandbox Code Playgroud)

此扩展使用返回可选的转换函数,并返回仅包含未转换为nil的值的数组

为什么不用self.map(transform)?这里有懒惰吗?

Mar*_*n R 11

它避免了创建中间数组.

self.map(transform)
Run Code Online (Sandbox Code Playgroud)

返回一个数组,其中包含所有序列元素转换的结果, 然后遍历这些数组以使用非零元素构建结果数组.

lazy(self).map(transform)
Run Code Online (Sandbox Code Playgroud)

是变换元素的序列,然后迭代以获得非零元素.在枚举期间计算变换的元素.(next() 对惰性序列的每次调用都会通过转换原始序列的下一个元素来生成一个元素.)

两种方法都有效.惰性方法可能对大型序列执行得更好,但这可能取决于许多因素(数组的大小,元素是值或引用类型,复制数组元素的成本等).对于小型数组,由于额外的开销,惰性方法可能会更慢.在具体的应用程序中,使用Instruments进行分析将有助于确定使用哪种方法.


Qby*_*yte 5

正如Martin R所提到的那样,lazy()避免了中间数组的创建.但是,如果我在不同大小的数组上比较函数的执行时间,你会发现lazy()"仅"快10%.

有趣的是,您发现lazy()对于少于200个元素的数组来说,速度快2倍,并且使用更多元素几乎与没有转换的函数一样快(速度提高10%).

(在Playground中使用Xcode 6.4和Xcode 7作为(编译的)源文件中的全局函数和协议扩展进行测试)

所以lazy()宁愿用于Sequences你不知道它是否有限的地方.然后,for循环可能与breakor一起使用return:

for element in lazy(sequence).map{ ... } {
    if element == 1000 {
        break
    }
    // use element
}
Run Code Online (Sandbox Code Playgroud)

如果你在无限上调用map Sequence(比如1,2,3 ......),那么执行也是无限的.随着lazy()转换和执行变得"延迟",因此如果你在最后一个元素之前突破循环,你可以更有效地处理"大"和无限序列.