Sequences für for ... in - wurzelsand/swift-memos GitHub Wiki

Sequences für for ... in

Themen

  • Protocol Sequence und IteratorProtocol
  • subscript

Aufgabe

Ich hätte gerne eine Colors-Struktur, die sich wie ein Array verhält:

var colors = Colors()
for color in colors {
    print(color) // Red Green Blue Yellow
}
colors[0] = "Black"
print(colors[0]) // Black

Ausführung

struct Colors {
    var values: [String] = ["Red", "Green", "Blue", "Yellow"]
    
    subscript(i: Int) -> String {
        get {
            values[i]
        }
        set {
            values[i] = newValue
        }
    }
}

extension Colors: Sequence {
    func makeIterator() -> ColorsIterator {
        ColorsIterator(values: values)
    }
}

struct ColorsIterator: IteratorProtocol {
    let values: [String]
    var index = 0
    
    init(values: [String]) {
        self.values = values
    }
    
    mutating func next() -> String? {
        if index >= values.count {
            return nil
        }
        defer {
            index += 1
        }
        return values[index]
    }
}

Anmerkungen

Hier geht es auch einfacher:

extension Colors: Sequence {
    func makeIterator() -> IndexingIterator<[String]> {
        values.makeIterator()
    }
}

Wenn ich selber einen generischen IndexingIterator erstellen möchte:

struct ColorsIterator<Elements>: IteratorProtocol where Elements: Collection {
    typealias Element = Elements.Element

    let values: Elements
    var index: Elements.Index

    init(values: Elements) {
        self.values = values
        self.index = values.startIndex
    }

    mutating func next() -> Element? {
        if index == values.endIndex {
            return nil
        }
        defer {
            index = values.index(after: index)
        }
        return values[index]
    }
}

extension Colors: Sequence {
    func makeIterator() -> ColorsIterator<[String]> {
        ColorsIterator(values: self.values)
    }
}
  • Wenn ich wirklich nur Arrays erlauben möchte:

    struct ColorsIterator<T>: IteratorProtocol {
        
        let values: [T]
        var index = 0
    
        init(values: [T]) {
            self.values = values
        }
    
        mutating func next() -> T? {
            if index >= values.count {
                return nil
            }
            defer {
                index += 1
            }
            return values[index]
        }
    }
    
    extension Colors: Sequence {
        func makeIterator() -> ColorsIterator<String> {
            ColorsIterator(values: self.values)
        }
    }

    Beachte, dass makeIterator nicht ColorsIterator<[String]> sondern ColorsIterator<String> zurückgibt.

⚠️ **GitHub.com Fallback** ⚠️