斯威夫特的懒惰

时间:2015-07-05 14:35:58

标签: 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)
        }
        return result
    }
}

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

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

2 个答案:

答案 0 :(得分:11)

它避免了创建中间数组。

self.map(transform)

返回包含转换结果的数组 所有序列元素,然后遍历以构建 结果数组包含非零元素。

lazy(self).map(transform)

是转换元素的序列,然后是 迭代以获得非零元素。转化的元素 在枚举期间计算。 (每次致电next() 在惰性序列上通过转换下一个元素产生一个元素 原始序列的元素。)

两种方法都有效。惰性方法可能会表现得更好 对于大型序列,但这可能取决于许多因素(大小 对于数组,无论元素是值还是引用类型, 复制数组元素的成本是多少等)。适用于小型阵列 懒惰的方法可能会因为额外的而变慢 高架。在具体的应用程序中,使用Instruments进行分析 帮助决定使用哪种方法。

答案 1 :(得分:5)

正如Martin R所提到的那样lazy()避免了中间数组的创建。但是,如果我将函数的执行时间与不同大小的数组进行比较,您会发现lazy()“仅”加快了10%。

有趣的是,您发现lazy()适用于少于200个元素的数组,速度快2倍,并且获得的元素数量几乎与没有转换的函数相同(快10%)。

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

所以lazy()宁愿用于Sequences,你不知道它是否是有限的。然后,for循环可能与breakreturn

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

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