gpt4 book ai didi

swift - 在迭代期间使用 forEach 从集合中删除元素

转载 作者:行者123 更新时间:2023-11-30 12:42:38 24 4
gpt4 key购买 nike

最近,我没有多想就写了这段代码:

myObject.myCollection.forEach { myObject.removeItem($0) }

其中 myObject.removeItem(_)myObject.myCollection 中删除项目。

现在看看代码,我很困惑为什么这会起作用 - 我不应该得到类似于 Collection was mutated while being enumerated 的异常吗?相同的代码甚至在使用常规 for-in 循环时也能工作!

这是预期的行为还是我“幸运”它没有崩溃?

最佳答案

这确实是预期的行为 - 这是因为 Swift 中的Array(以及标准库中的许多其他集合)是一种具有写时复制语义的值类型。这意味着它的底层缓冲区(间接存储)将在发生变异时复制(并且,作为一种优化,仅当它没有被唯一引用时)。

当您要迭代序列(例如数组)时,可以使用forEach(_:)或标准for in 循环,从序列的 makeIterator() 创建一个迭代器方法及其 next()重复应用方法以顺序生成元素。

您可以将序列迭代视为如下所示:

let sequence = [1, 2, 3, 4]
var iterator = sequence.makeIterator()

// `next()` will return the next element, or `nil` if
// it has reached the end sequence.
while let element = iterator.next() {
// do something with the element
}

对于数组IndexingIterator用作其迭代器 - 它将通过简单地存储该集合以及迭代的当前索引来迭代给定集合的元素。每次调用 next() 时,基集合都会使用索引作为下标,然后递增,直到达到 endIndex (您可以看到其 exact implementation here )。

因此,当您在循环中改变数组时,其底层缓冲区不是唯一引用的,因为迭代器也可以查看它。这会强制创建缓冲区的副本 - 然后 myCollection 使用该副本。

因此,现在有两个数组 - 一个正在迭代,另一个正在改变。只要 myCollection 的缓冲区保持唯一引用,循环中的任何进一步突变都不会触发另一个副本。

因此,这意味着在枚举集合时用值语义改变集合是完全安全的。枚举将迭代集合的整个长度 - 完全独立于您所做的任何突变,因为它们将在副本上完成。

关于swift - 在迭代期间使用 forEach 从集合中删除元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42055194/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com