2014-07-04 4 views
5

Kann jemand erklären, was im folgenden Code passiert? Es erzeugt eine Struktur Either, die zwei beliebige optionale Typen verwendet und (versucht) das zurückgibt, was nicht gleich null ist, oder das erste, wenn beide nicht null sind. Aber es verhält sich seltsam, wenn wörtliche Null vorbei wie in zu einem Null-Variable gegenüber. Ich kann nicht sehen, warum b4 im Beispiel verhält, wie es funktioniert ...Implementieren von "Entweder" -Struktur in Swift

struct Either <T1, T2> { 
    let first: T1? 
    let second: T2? 

    init(first: T1?, second: T2?) { 
     self.first = first 
     self.second = second 
    } 

    func either() -> Bool { 
     return (self.first != nil) || (self.second != nil) 
    } 

    func which() -> Any? { 
     if self.first != nil { 
      return self.first 
     } else if self.second != nil { 
      return self.second 
     } 
     return nil 
    } 
} 

var s1: String? = nil 
var s2: Int? = nil 

let b1 = Either(first: s1, second: s2) 
b1.either() // false 
b1.which() // {nil} 

s1 = "Hello" 
let b2 = Either(first: s1, second: s2) 
b2.either() // true 
b2.which() // {Some Hello} 

s1 = nil 
s2 = 7 
let b3 = Either(first: s1, second: s2) 
b3.either() // true 
b3.which() // {Some 7} 

// all as expected, however 
let b4 = Either(first: nil, second: nil) 
b4.either() // true !!! <<<<<<<<<<<<<<<<<< 
b4.which() // {nil} 

Ich denke, es mit „Optional zu tun hat Optionals ", aber ich bin mir nicht sicher, ob es sich wie erwartet verhält.

Antwort

6

Dies hat in Beta 3, der letzten Fall löst nun korrekt einen Compiler-Fehler zwingen Sie den generischen Typen explizit

Das Problem in Typen festlegen fest - wenn Either von Literalen erstellen:

let b4 = Either(first: nil, second: nil) 

dann kann der Compiler den Typ für die nil Parameter nicht ableiten. Wenn Sie den Debugger überprüfen, sehen Sie, dass der abgeleitete Typ ein Typ ist, der _Nil genannt wird.

(lldb) p b4 
(SwiftConsole.Either<_Nil, _Nil>) $R1 = { 
    first = Some 
    second = Some 
} 

Nun, dies ist eine Art, die nil akzeptiert, aber es ist nicht ein optionaler Typ selbst.

let x: _Nil = nil //this is not an optional 

Die initialiser machen eine optionale davon, so dass ein Wert machen Optional.Some(nil) und weil es ein .Some(...) Wert, es mit nil Vergleich false sein wird.

Ich sehe keine einfache allgemeine Abhilfen aber in diesem Fall würde es helfen, explizit generische Typen angeben:

let b4 = Either<String, Int>(first: nil, second: nil) 

Ich schlage vor, Sie einen Fehler melden, da dies nur dumm ist. Anstatt einige spezielle Typen abzuleiten, die zu undefiniertem Verhalten führen, sollte der Compiler stattdessen einen Fehler auslösen.

Das gleiche Problem würde mit Typ Any auftreten, weil es auch nil akzeptieren kann, ohne ein optionales sein.

let x: Any = nil //this is not an optional 

Either<Any, Any>(first: nil, second: nil).which() //true !!! 

Edit: Dies wird in Beta behoben werden 3. nil wird eine wörtliche, gemacht werden _Nil Typ entfernt werden und _Any nicht nil mehr akzeptieren.

hier Bestätigt: https://devforums.apple.com/thread/234463?tstart=0

+0

Danke für den Link, @Sulthan. Das Hinzufügen der "if let" -Klauseln, die sie vorgeschlagen haben, machte keinen Unterschied, aber ihre Schlussbemerkung "Vielleicht mischen Sie nicht optionals und Any" ist ... gut ... weniger als ideal! Ich finde es besorgniserregend, dass ich nicht vorhersagen/rationalisieren kann, warum das passiert. – Grimxn

+0

'let b4 = Entweder (zuerst: Null, Sekunde: Null)' funktioniert, wie Sie vorschlagen. Horror. – Grimxn

+0

@Grimxn Ich habe gerade Xcode und musste meine Antwort bearbeiten, weil das Problem komplizierter ist, als ich ursprünglich dachte. – Sulthan

Verwandte Themen