2016-04-08 11 views
1

Der Kontext: Ich habe einen generischen Stapel von Objekten. Der Stapel reagiert() Pop (gibt einen optional), und ich habe eine Funktion, die den StapelWährend optional, unwrap, wenn etwas enthält

  • verarbeiten muss Wenn der Stapel leer ist, andernfalls
  • einen Fehler aus, wiederholen Sie die Wiederholungs-Modus bis zum nächsten optional nicht unwrappable

Bisher

guard var nextVar = myStack.pop() else { 
    throw MyError.EmptyStack 
} 

repeat { 
    // Process nextVar 
} while nextVar = myStack.pop() 

Problem: die erste nextVar ist kein optionale daher nicht mein während Anruf. Wie kann ich neu schreiben, so dass die while überprüft, ob das optionale enthält etwas Und wenn das gelingt, den Inhalt der Variablen zuweisen?()

Antwort

3

Sie sollten Ihren Stapeltyp so ändern, dass er eine isEmpty-Eigenschaft enthält. Dann müssen Sie den pop Anruf nicht duplizieren, und das wird eine einfache while-let Schleife sein.

guard !myStack.isEmpty else { 
    throw MyError.EmptyStack 
} 

while let nextVar = myStack.pop() { 
    // Process nextVar 
} 

Sie können auch diese in eine SequenceType, konvertieren, aber dann wird das Iterieren den Stapel nicht verbrauchen. Dann wäre dies nur sein:

guard !myStack.isEmpty else { 
    throw MyError.EmptyStack 
} 

for nextVar in myStack { 
    // Process nextVar 
} 

Da pop ist genau die benötigte Umsetzung GeneratorType.next(), sollte es leicht sein, dies zu drehen in ein GeneratorType und ein SequenceType (von self in generate() Rückkehr).

Aber da Stack ein Werttyp ist, wird eine Iteration mit for-in eine Kopie erstellen und dann diese Kopie konsumieren, anstatt den ursprünglichen Stapel zu verbrauchen. Das könnte gut oder schlecht sein.

Hier ist eine Skizze von dem, was ich meine:

struct Stack<Element> { 
    private var stack: [Element] = [] 
    mutating func push(element: Element) { 
     stack.append(element) 
    } 

    mutating func pop() -> Element? { 
     guard let result = stack.last else { return nil } 
     stack.removeLast() 
     return result 
    } 

    var isEmpty: Bool { return stack.isEmpty } 
} 

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

extension Stack: SequenceType { 
    func generate() -> Stack { 
     return self 
    } 
} 
+1

Minor Bemerkung: Wenn Sie beide SequenceType annehmen * und * GeneratorType dann müssen Sie nicht implementieren erzeugen(), gibt es eine Default-Implementierung. –