shoujs
shoujs

Reputation: 1143

Why mutating function next does not change the struct (conforming to Sequence and IteratorProtocol) after the iteration?

I write a stack struct, and make it conforming to IteratorProtocol and Sequence protocol. The next function is mutating. So I suppose the iteration of the stack will mutate the struct.

import Foundation


struct Stack<Element> {
    var store:[Element] = []

    mutating func push(_ element:Element) {
        store.append(element)
    }

    mutating func pop() -> Element? {
        return store.popLast()
    }
}


extension Stack: Sequence, IteratorProtocol {

    mutating func next() -> Element? {
        return pop()
    }

}

var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.push(3)


for s in stack {
    print(s)
}

print(stack)

Here is the console output: enter image description here

I don't understand why the stack is unchanged. I suppose it become empty after the mutating next() calls.

Upvotes: 1

Views: 264

Answers (1)

Benno Kress
Benno Kress

Reputation: 2809

Your for ... in-Loop works on a copy of stack and never changes the stack itself. If you were to call next() yourself, the pop() would modify the stack as you can see here:

import Foundation

struct Stack<Element> {
    var store: [Element] = []

    mutating func push(_ element:Element) {
        store.append(element)
    }

    mutating func pop() -> Element? {
        return store.popLast()
    }
}


extension Stack: Sequence, IteratorProtocol {
    mutating func next() -> Element? {
        return pop()
    }
}

var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.push(3)

for s in stack {
    print(s)
}

stack.next()

print(stack.store)

Output:

3
2
1
[1, 2]

However as @user3581248 pointed out in the comments, making Stack a class instead of a struct (and removing mutating from its functions) gives you the desired behavior.

Upvotes: 2

Related Questions