Swift: test par rapport à la valeur optionnelle dans le boîtier du commutateur

89

Dans Swift, comment puis-je écrire un cas dans une instruction switch qui teste la valeur commutée par rapport au contenu d'un optionnel , en sautant le cas si le optionnel contient nil?

Voici à quoi j'imagine que cela pourrait ressembler:

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
}

Si je viens d' écrire exactement comme ça, le compilateur se plaint que someOptionaln'est pas déballés, mais si je explicitement Déballer en ajoutant !à la fin, je cours d'obtenir une erreur d'exécution tout moment someOptionalcontient nil. Ajouter à la ?place de !aurait du sens pour moi (dans l'esprit du chaînage optionnel, je suppose), mais ne fait pas disparaître l'erreur du compilateur (c'est-à-dire qu'il ne déballe pas réellement l'option).

George WS
la source

Réponses:

112

Facultatif est juste un enumcomme ceci:

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

    // ...
}

Vous pouvez donc les faire correspondre comme d'habitude avec les modèles de correspondance "Valeurs associées" :

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")
}

Si vous voulez une correspondance à partir de someValue, en utilisant l' expression de garde :

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

Et pour Swift> 2.0

switch someValue {
case let val where val == someOptional:
    print("matched")
default:
    print("didn't match; default")        
}
Rintaro
la source
4
Notez que dans Swift 3, certains / aucun sont en minuscules, c'est-à-dire que vous utiliseriez .some au lieu de .Some
Adam
53

À partir de Xcode 7 (à partir des notes de version de la version bêta 1), "un nouveau x?modèle peut être utilisé pour la correspondance de modèles avec des options en tant que synonyme de .Some(x)." Cela signifie que dans Xcode 7 et versions ultérieures, la variante suivante de la réponse de rintaro fonctionnera également:

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
la source
3
La question est de faire correspondre une valeur non facultative à une valeur facultative, cette réponse est l'inverse.
Martin R
2
Certes, cependant, cette réponse a été écrite à l'origine par l'OP comme une mise à jour de la question, donc pour lui, c'était une solution irréfutable; Je viens de le déplacer vers une réponse wiki de la communauté. Peut-être que @GeorgeWS peut clarifier pourquoi la commutation des arguments de commutateur et de cas fonctionne pour son cas d'utilisation?
Slipp D.Thompson
2
Je suis un peu perdue. quelle est la différence entre vos deux premiers cas? someValue?est une autre valeur définie, mais case let val?est-ce juste la version non emballée sûre de someOptional?!
Honey
@Honey Ce n'est pas un exemple de code réel; c'est simplement une variation de la réponse de Rintaro. Alors allez lui poser cette question - ma réponse est fonctionnellement équivalente au code dans le sien. Si vous posiez la question à rintaro, je crois que la réponse serait 1. Cela reflète ce qui se trouve dans les documents Apple liés; 2. il ne montre que la syntaxe; il n'accomplit pas un objectif de calcul ou de logique métier distinct.
Slipp D.Thompson
@Honey De plus, la réponse de rintaro a été écrite à l'origine pour Swift 1.x et mise à jour pour Swift 2. Il est possible que la version sans letne se compile plus. Je ne me souviens pas pour le moment pourquoi cela aurait fonctionné à l'époque.
Slipp D.Thompson
10

Dans Swift 4, vous pouvez utiliser Optional: ExpressibleByNilLiteral of Apple pour envelopper facultatif

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

Exemple

enum MyEnum {
    case normal
    case cool
}

certains

let myOptional: MyEnum? = MyEnum.normal

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

    case .none: 
    break

    default:
    break
}

aucun

let myOptional: MyEnum? = nil

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

    case .none: 
    // Found nil
    break

    default:
    break
}

défaut

let myOptional: MyEnum? = MyEnum.cool

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

    case .none: 
    break

    default:
    // Found .Cool enum
    break
}

Énumération avec valeur

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

une certaine valeur

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
la source