Swift: Testen gegen optionalen Wert im Schaltergehäuse

89

Wie kann ich in Swift einen Fall in eine switch-Anweisung schreiben, die den Wert, der umgeschaltet wird, mit dem Inhalt einer Option vergleicht und den Fall überspringt, wenn die Option enthält nil?

So stelle ich mir das vor:

let someValue = 5
let someOptional: Int? = nil

switch someValue {
case someOptional:
    // someOptional is non-nil, and someValue equals the unwrapped contents of someOptional
default:
    // either, someOptional is nil, or someOptional is non-nil but someValue does not equal the unwrapped contents of someOptional
}

Wenn ich es nur schreiben genau so, beschwert sich der Compiler , dass someOptionalnicht ausgepackt ist, aber wenn ich unwrap es ausdrücklich durch Zugabe !bis zum Ende, ich natürlich einen Laufzeitfehler erhalten jederzeit someOptionalenthält nil. Das Hinzufügen ?statt !würde für mich einen Sinn ergeben (im Geiste der optionalen Verkettung, nehme ich an), lässt aber den Compilerfehler nicht verschwinden (dh das optionale nicht auspacken).

George WS
quelle

Antworten:

112

Optional ist einfach enumso:

enum Optional<T> : Reflectable, NilLiteralConvertible {
    case None
    case Some(T)

    // ...
}

So können Sie sie wie gewohnt mit "Assoziierten Werten" abgleichen:

let someValue = 5
let someOptional: Int? = nil

switch someOptional {
case .Some(someValue):
    println("the value is \(someValue)")
case .Some(let val):
    println("the value is \(val)")
default:
    println("nil")
}

Wenn Sie eine Übereinstimmung von möchten someValue, verwenden Sie den Schutzausdruck :

switch someValue {
case let val where val == someOptional:
    println(someValue)
default:
    break
}

Und für Swift> 2.0

switch someValue {
case let val where val == someOptional:
    print("matched")
default:
    print("didn't match; default")        
}
Rintaro
quelle
4
Beachten Sie, dass in Swift 3 einige / keine Kleinbuchstaben sind, dh Sie würden .some anstelle von .Some verwenden
Adam
52

Ab Xcode 7 (aus den Beta 1-Versionshinweisen) kann "ein neues x?Muster verwendet werden, um Musterübereinstimmungen mit Optionen als Synonym für .Some(x)". Dies bedeutet, dass in Xcode 7 und höher auch die folgende Variante der Antwort von rintaro funktioniert:

let knownValue = 5

switch someOptional {
case knownValue?:
    // Contents of someOptional are knownValue, defined above.
case let otherValue?:
    // Contents of someOptional are *any* non-nil value not already tested for.
    // Unwrapped contents are assigned to otherValue for use inside this case.
default:
    // someOptional is nil.
}
Slipp D. Thompson
quelle
3
Bei der Frage geht es darum, einen nicht optionalen Wert mit einem optionalen Wert abzugleichen. Diese Antwort ist umgekehrt.
Martin R
2
Diese Antwort wurde zwar ursprünglich vom OP als Aktualisierung der Frage verfasst, so dass sie für ihn unwiderlegbar eine praktikable Lösung war. Ich habe es gerade in eine Community-Wiki-Antwort verschoben. Vielleicht kann @GeorgeWS klarstellen, warum das Umschalten der Schalter- und Fallargumente für seinen Anwendungsfall funktioniert?
Slipp D. Thompson
2
Ich bin ein bisschen verloren. Was ist der Unterschied zwischen Ihren ersten beiden Fällen? someValue?ist ein anderer definierter Wert, aber case let val?ist nur die sichere unverpackte Version von someOptional?!
Honig
@Honey Es ist kein reales Codebeispiel; Es ist einfach eine Variation von Rintaros Antwort. Stellen Sie ihm / ihr diese Frage - meine Antwort entspricht funktional dem Code in seiner / ihrer. Wenn Sie jedoch Rintaro fragen würden, wäre die Antwort meiner Meinung nach 1. Sie spiegelt wider, was in den verknüpften Apple-Dokumenten enthalten ist. 2. es zeigt nur die Syntax; Es wird kein eindeutiges Berechnungs- oder Geschäftslogikziel erreicht.
Slipp D. Thompson
@Honey Außerdem wurde Rintaros Antwort ursprünglich für Swift 1.x geschrieben und für Swift 2 aktualisiert. Es ist möglich, dass die Version letnicht mehr kompiliert wird. Ich kann mich jetzt nicht erinnern, warum das früher funktioniert hätte.
Slipp D. Thompson
9

In Swift 4 können Sie Optional: ExpressibleByNilLiteral von Apple verwenden, um optional zu verpacken

https://developer.apple.com/documentation/swift/optional

Beispiel

enum MyEnum {
    case normal
    case cool
}

etwas

let myOptional: MyEnum? = MyEnum.normal

switch smyOptional {
    case .some(.normal): 
    // Found .normal enum
    break

    case .none: 
    break

    default:
    break
}

keiner

let myOptional: MyEnum? = nil

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    // Found nil
    break

    default:
    break
}

Standard

let myOptional: MyEnum? = MyEnum.cool

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    break

    default:
    // Found .Cool enum
    break
}

Aufzählung mit Wert

enum MyEnum {
    case normal(myValue: String)
    case cool
}

ein Wert

let myOptional: MyEnum? = MyEnum.normal("BlaBla")

switch smyOptional {
case .some(.normal(let myValue)) where myValue == "BlaBla":
    // Here because where find in my myValue "BlaBla"
    break

// Example for get value
case .some(.normal(let myValue)):
    break

// Example for just know if is normal case enum
case .some(.normal):
    break

case .none:
    break

default:

    break
}
YannSteph
quelle