当我编写具有高阶函数的代码时,我发现一次写出一个转换表达式会更加清晰:
let children = objects.map { $0.children }
let validChildren = children.filter { $0.isValid }
let sortedChildren = validChildren.sorted { $0.count < $1.count }
但是,我知道这些函数中的每一个都返回一个新的Array对象,我将它存储到一个变量中,所以理论上我每次创建并持有一个新的Array并浪费大量内存。最好将调用写为一行,以便在使用后销毁不必要的数组。
let sortedChildren = objects.map { $0.children } .filter { $0.isValid } .sorted { $0.count < $1.count }
但是稍后阅读会更加烦人,因为在一行代码中会发生很多事情。所以我的问题是:Swift的编译器是否有优化来原谅我的挑剔并在编译时删除未使用的变量?
答案 0 :(得分:1)
@MartinR在问题评论中提到了这一点,但值得一个正式答案和来源。
As per the Swift repository docs:
Swift中的所有标准库容器都是使用COW的值类型 (copy-on-write)[4]执行复制而不是显式复制。在 在许多情况下,这允许编译器通过它来消除不必要的副本 保留容器而不是执行深层复制。这是 仅通过复制基础容器(如果引用计数)来完成 容器大于1,容器发生变异。对于 在下面的实例中,分配d时不会发生复制 c,但当d通过附加2进行结构变异时,d将是 复制,然后2将附加到d:
var c: [Int] = [ ... ]
var d = c // No copy will occur here.
d.append(2) // A copy *does* occur here.
由于高阶函数不会修改它们被调用的对象,因此可以高度放心地说结果针对大小进行了优化。
答案 1 :(得分:1)
两个版本之间没有区别。
即使您没有将结果分配给变量,也会创建一个新的列表实例,以便存储函数调用的结果。因此,内存使用情况是相同的。
objects.map { $0.children }.filter { $0.isValid }.sorted { $0.count < $1.count }
所以在每次函数调用之后,我们仍然需要内存来存储该函数的结果,无论你是assign
它还是变量。并且assigning
到另一个变量不会制作该对象的任何副本。