常量序列可以使用for-in循环迭代,但不能直接调用next()?
a constant sequence can iterate using for-in loop, but can't call next() directly?
在下面的代码中,c
是一个常量序列(Countdown
的一个实例),它可以遍历它的元素并在满足条件时中断,它可以从重新开始。
但是当我直接调用 c.next()
时,我得到一个编译器错误:cannot use mutating member on immutable value.
所以,我有两个问题:
- 如果我不能调用
c.next()
,为什么它可以首先遍历所有元素?不是在内部使用next()
方法来遍历它们吗?
- 在下面代码的第二个
for-in
循环中,为什么不是从第一次迭代结束的1
开始计数,而是从头开始计数,即3
]?
struct Countdown: Sequence, IteratorProtocol {
// internal state
var count: Int
// IteratorProtocol requirement
mutating func next() -> Int? {
if count == 0 { return nil } else {
defer { count -= 1 }
return count
}
}
}
// a constant sequence
let c = Countdown(count: 3)
// can iterate and break
for i in c {
print(i) // 3, 2
if i == 2 { break }
}
// iterate again from start (not from 1, why?)
for i in c { print(i) } // 3, 2, 1
// ⛔️ Error: cannot use mutating member on immutable value.
// `c` is a `let` constant.
c.next()
因为每个 for
循环都通过调用序列的 makeIterator()
函数来创建一个新的迭代器,它是由标准库在 Sequence
的条件表达式中定义的,但是仅当符合序列也符合 IteratorProtcol
,就像你的一样。
对 for
循环进行脱糖揭示了问题所在:
let c = Countdown(from: 3)
var iterator1 = c.makeIterator()
while let i = iterator1.next() {
print(i) // 3, 2
if i == 2 { break }
}
var iterator2 = c.makeIterator()
while let i = iterator2.next() { print(i) } // 3, 2, 1
制作了两个独立的迭代器,每个 for
循环一个。每个 "starts fresh" 都源自 c
的副本(从未发生过变异)。
您不能调用 next
,因为 next
是 mutating
。 next
改变迭代器的状态,使其"moves closer"结束。
for
循环不直接调用 next
。它创建 c
(var
) 的 mutable 副本,并调用 next
:
// The for loop basically does this:
var copy = c // creates a copy
var element = copy.next()
element = copy.next()
element = copy.next()
...
第二个for循环之所以从头开始,就是因为这个。 for
循环实际上并不会改变你正在迭代的事物的状态。他们创建一个副本,使用该副本,然后将其丢弃。
避免这种复制行为的一种方法是将 Countdown
设为 class:
class Countdown: Sequence, IteratorProtocol {
// internal state
var count: Int
// IteratorProtocol requirement
func next() -> Int? {
if count == 0 { return nil } else {
defer { count -= 1 }
return count
}
}
init(from n: Int){
count = n
}
}
在下面的代码中,c
是一个常量序列(Countdown
的一个实例),它可以遍历它的元素并在满足条件时中断,它可以从重新开始。
但是当我直接调用 c.next()
时,我得到一个编译器错误:cannot use mutating member on immutable value.
所以,我有两个问题:
- 如果我不能调用
c.next()
,为什么它可以首先遍历所有元素?不是在内部使用next()
方法来遍历它们吗? - 在下面代码的第二个
for-in
循环中,为什么不是从第一次迭代结束的1
开始计数,而是从头开始计数,即3
]?
struct Countdown: Sequence, IteratorProtocol {
// internal state
var count: Int
// IteratorProtocol requirement
mutating func next() -> Int? {
if count == 0 { return nil } else {
defer { count -= 1 }
return count
}
}
}
// a constant sequence
let c = Countdown(count: 3)
// can iterate and break
for i in c {
print(i) // 3, 2
if i == 2 { break }
}
// iterate again from start (not from 1, why?)
for i in c { print(i) } // 3, 2, 1
// ⛔️ Error: cannot use mutating member on immutable value.
// `c` is a `let` constant.
c.next()
因为每个 for
循环都通过调用序列的 makeIterator()
函数来创建一个新的迭代器,它是由标准库在 Sequence
的条件表达式中定义的,但是仅当符合序列也符合 IteratorProtcol
,就像你的一样。
对 for
循环进行脱糖揭示了问题所在:
let c = Countdown(from: 3)
var iterator1 = c.makeIterator()
while let i = iterator1.next() {
print(i) // 3, 2
if i == 2 { break }
}
var iterator2 = c.makeIterator()
while let i = iterator2.next() { print(i) } // 3, 2, 1
制作了两个独立的迭代器,每个 for
循环一个。每个 "starts fresh" 都源自 c
的副本(从未发生过变异)。
您不能调用 next
,因为 next
是 mutating
。 next
改变迭代器的状态,使其"moves closer"结束。
for
循环不直接调用 next
。它创建 c
(var
) 的 mutable 副本,并调用 next
:
// The for loop basically does this:
var copy = c // creates a copy
var element = copy.next()
element = copy.next()
element = copy.next()
...
第二个for循环之所以从头开始,就是因为这个。 for
循环实际上并不会改变你正在迭代的事物的状态。他们创建一个副本,使用该副本,然后将其丢弃。
避免这种复制行为的一种方法是将 Countdown
设为 class:
class Countdown: Sequence, IteratorProtocol {
// internal state
var count: Int
// IteratorProtocol requirement
func next() -> Int? {
if count == 0 { return nil } else {
defer { count -= 1 }
return count
}
}
init(from n: Int){
count = n
}
}