Swift中Collection的map函数实现与实际行为为何不一致?
Swift Array.map 行为与源码的差异原因
你看到的Collection.map源码逻辑是遍历原集合下标,逐个取出元素传入transform闭包,最终返回结果数组。但测试代码里修改原数组变量后,map返回结果仍为原数组初始值,核心原因在于Swift Array是值类型,闭包中修改的是变量指向的新数组实例,而map方法内的self是调用map时的原数组实例。
具体执行过程拆解
你的测试代码执行步骤如下:
- 初始化
var array = [0, 1, 2],此时变量array指向一个值为[0,1,2]的Array实例(记为实例A)。 - 调用
array.map,此时map方法的self绑定的是实例A——值类型的实例方法调用时,self是当前变量指向的实例本身。 - 进入
map循环:- 第一次循环:取
self[0]即实例A的第一个元素0传入闭包。闭包执行array[0] = -1,这会创建一个新的Array实例(实例B,值为[-1,1,2]),并将变量array的指向从实例A切换为实例B。闭包返回0,添加到结果数组。 - 第二次循环:取
self[1]即实例A的第二个元素1传入闭包。闭包执行array[1] = -1,此时变量array指向实例B,这会生成新实例C(值为[-1,-1,2]),array指向更新为实例C。闭包返回1,添加到结果数组。 - 第三次循环:取
self[2]即实例A的第三个元素2传入闭包。闭包执行array[2] = -1,此时array指向实例C,生成新实例D(值为[-1,-1,-1]),array指向更新为实例D。闭包返回2,添加到结果数组。
- 第一次循环:取
map返回结果数组[0,1,2],此时变量array指向实例D,因此打印array得到[-1,-1,-1]。
为何看起来和“源码逻辑不一致”
你误解了self的指向:map方法里的self是调用map瞬间的原数组实例(实例A),闭包中修改的是变量array的指向,后续所有修改都不会影响实例A的内容。所以map遍历的始终是实例A的初始元素,返回结果自然和初始值一致,这完全符合源码逻辑。
如果要验证源码的遍历逻辑(修改原实例元素是否会影响map遍历),可以用引用类型包装数组来避免值类型拷贝:
class WrappedArray { var elements: [Int] init(_ elements: [Int]) { self.elements = elements } } var wrapped = WrappedArray([0,1,2]) let newArray = wrapped.elements.map { element -> Int in wrapped.elements[2] = -1 return element } print(wrapped.elements) // 输出 [-1,-1,-1] print(newArray) // 输出 [0,1,-1]
这个例子中,wrapped.elements是引用类型的属性,闭包修改的是同一个数组实例,map遍历到第三次时,self[2]已被修改为-1,返回结果和你最初的预期一致。
内容的提问来源于stack exchange,提问作者Yasic
相关产品推荐
相关产品推荐

