for ... in 循环是否循环遍历序列的副本?

问题描述 投票:0回答:3

我在 Matt Neuburg 的 iOS 13 Swift 编程基础中遇到了如下陈述:

当您使用 for...in 循环遍历序列时,您实际上循环的是该序列的副本。这意味着在循环序列时改变序列是安全的:

作者为上述陈述提供了以下示例:

var s : Set = [1,2,3,4,5]
for i in s {
    if i.isMultiple(of:2) {
        s.remove(i)
    }
} // s is now [1,3,5]

在上面的示例中,我们可以看到原始数组从 [1,2,3,4,5,6] 更改为 [1,3,5]。这意味着数组本身已更改。因此,

for in
循环不是循环遍历原始数组的副本,而是循环数组本身。这似乎与作者上述的说法相矛盾。

所以,我不确定作者的说法是否属实。有人愿意澄清一下这个问题吗?非常感谢。

arrays swift loops for-in-loop
3个回答
5
投票

乍一看,措辞可能有点误导,但

for i in s
循环遍历原始
s
的副本的说法是正确的。如果不是这样,您将得到越界异常或意外结果(集合的某些元素被跳过),因为您在迭代集合时会改变集合。

当您使用

for i in s
创建循环时,会创建
s
的副本,并通过该副本进行迭代。但是,当您在循环体内访问
s
时,您正在访问原始
s
并因此对其进行更改,而不是更改循环正在迭代的副本。


4
投票

这里有一点细微差别。您迭代的数组是副本,但您正在修改的数组仍然是原始数组。

在其他情况下,由于索引更改,此代码最终会跳过一些元素。

如果情况并非如此,请考虑以下迭代

// i = 0
// s = [1,2,3,4,5]
// evaluation 1.isMultiple(of: 2)
// element to be removed: none
// i = 1
// s = [1,2,3,4,5]
// evaluation 2.isMultiple(of: 2)
// element to be removed: 2
// Here is where the problems would start, since the number 3 would be skipped.
// i = 2
// s = [1,3,4,5]
// evaluation 4.isMultiple(of: 2)
// element to be removed: 2

由于您正在迭代副本,因此您可以修改

s
并仍然确保所有元素都会被考虑。


0
投票

实际上,在某种程度上,你在写这篇文章时已经回答了你自己的问题,

这意味着数组本身已更改。

这是正确的,因为在

// s is now [1,3,5]
循环完成对序列的迭代之后,您最终得到了
for in
。问题出在后面那句话。

因此,for in 循环不是循环原始数组的副本,而是循环数组本身。

您的第一句话直接暗示 for in 循环是循环遍历原始数组的副本,而不是相反。

© www.soinside.com 2019 - 2024. All rights reserved.