2017-02-16 4 views
0

Ich AtomicBox von Matt Gallagher CwlUtils in einem kleinen Countdown mit:Muting Schließung wird nicht kompiliert, wenn es komplizierter als eine Anweisung ist - wie zu beheben?

class Countdown { 
    private let counter: AtomicBox<Int> 

    init(from start: Int) { 
     self.counter = AtomicBox(start) 
    } 

    func countDown() { 
     self.counter.mutate { $0 -= 1 } 
    } 
} 

Das funktioniert ganz gut. Nun sage ich möchte einen Fehler werfen, wenn der Zähler bereits Null erreicht hat:

func countDown() throws { 
    self.counter.mutate { 
     guard $0 > 0 else { 
      throw MyError.alreadyZero 
     } 

     $0 -= 1 
    } 
} 

jetzt swift build klagt: (. Weird-Fehlermeldung, nebenbei gesagt, sie kommen normalerweise schöner)

<unknown>:0: error: parameters may not have the 'var' specifier 
<unknown>:0: error: build had 1 command failures 
error: exit(1): /Applications/Xcode8.2/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool -f /Users/dhtp/Documents/CwlUtils/.build/debug.yaml 

Was geht hier vor? Beide Versionen mutieren den internen Wert von counter (der auf den Parameter mutate übertragen wird) in genau der gleichen Weise. Warum ist das eine legal und das andere nicht?

Wie kann ich die Schließung erklären, so dass es kompiliert (und macht was ich will)?

Ich versuchte { (inout value) in ... }, aber das gibt den gleichen Fehler.

Antwort

1

Die Schließung, die Sie übergeben, wird als Wurf deklariert. Der Compiler kann den Parameter auf den Abschluss nicht inout ableiten, da er nicht mit dem Schließungstyp übereinstimmt, den mutate erwartet.

Wenn Ihre Wache eine Aktion ausführt, die nicht ausgelöst wird, funktioniert sie wie erwartet.

self.counter.mutate { 
    guard $0 > 0 // Note the condition 
    else { print("I'm sorry Dave, I'm afraid I can't do that") ; return } 
    $0 -= 1 
} 

Die Fehlermeldung ist verwirrend. Sie sollten bei Swift.org wahrscheinlich einen Fehler melden.

+0

Meine Vermutung ist, dass der Compiler es irgendwie als Änderung der Funktion sieht, die an 'muate' übergeben wird. Art von funky. – PeejWeej

+0

[Fertig] (https://bugs.swift.org/browse/SR-3973), danke! – Raphael

+1

@PEEJWEEJ Eine Nicht-Wurf-Funktion wird als Spezialisierung der Wurffunktion mit denselben Parametern betrachtet, d.h. '(inout Int) -> Leere 'ist ein Subtyp von' (inout Int) Würfe -> Leere '. Sie können also eine Nicht-Wurf-Funktion verwenden, bei der der Parameter als Werfen deklariert ist, aber Sie können keine Wurf-Funktion verwenden, bei der der Parameter nicht als Werfen deklariert ist. – JeremyP

0

Wir müssen explizit neu deklarieren, dass der Parameter ist inout aus irgendeinem Grund:

self.counter.mutate { (value: inout Int) in 
    ... 
} 

wird wie erwartet.

Nun, im konkreten Fall können wir keinen Wurfverschluss an mutate übergeben, aber das ist ein anderes Problem.

+0

Eigentlich glaube ich nicht, dass es ein anderes Problem ist. Ich denke, es ist genau, weil die Schließung, die er passiert, zum Werfen erklärt wird. Der Compiler kann den Parameter für den Abschluss nicht inout ableiten, da er nicht mit dem Schließungstyp übereinstimmt, den mutate erwartet. – JeremyP

+0

@ JeremyP Ah, das macht Sinn. In diesem Fall ist "nur" die Compiler-Nachricht nicht hilfreich. Ich habe ein paar Mal bemerkt, dass wir keine Nachrichten bekommen "kann nicht etwas Nützliches ableiten, weil X", sondern stattdessen "[Ich habe mich still in eine Sackgasse gedrängt, und jetzt] gibt es einen Fehler Y". :/ – Raphael

Verwandte Themen