Swift: test rispetto al valore opzionale nel caso dello switch


89

In Swift, come posso scrivere un caso in un'istruzione switch che verifica il valore scambiato rispetto al contenuto di un facoltativo , saltando il caso se l'opzionale lo contiene nil?

Ecco come immagino che potrebbe apparire:

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
}

Se lo scrivo esattamente in questo modo, il compilatore si lamenta che someOptionalnon è scartato, ma se lo scarto esplicitamente aggiungendolo !alla fine, ovviamente ottengo un errore di runtime ogni volta che someOptionalcontiene nil. Aggiungere ?invece di !avrebbe un senso per me (nello spirito del concatenamento opzionale, suppongo), ma non fa sparire l'errore del compilatore (cioè non scartare effettivamente l'opzionale).

Risposte:


112

Opzionale è solo un enumcome questo:

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

    // ...
}

Quindi puoi abbinarli come al solito pattern di corrispondenza "Valori associati" :

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

Se vuoi la corrispondenza da someValue, usando l' espressione di guardia :

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

E per Swift> 2.0

switch someValue {
case let val where val == someOptional:
    print("matched")
default:
    print("didn't match; default")        
}

4
Nota che in Swift 3, alcuni / nessuno sono minuscoli, ovvero useresti .some invece di .Some
Adam

53

A partire da Xcode 7 (dalle note di rilascio beta 1), "un nuovo x?modello può essere utilizzato per la corrispondenza di modelli con optional come sinonimo di .Some(x)". Ciò significa che in Xcode 7 e versioni successive funzionerà anche la seguente variazione della risposta di rintaro :

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.
}

3
La domanda riguarda la corrispondenza di un valore non facoltativo con un facoltativo, questa risposta è il contrario.
Martin R

2
È vero, tuttavia questa risposta è stata originariamente scritta dal PO come aggiornamento della domanda, quindi per lui era inconfutabilmente una soluzione praticabile; L'ho appena spostato in una risposta wiki della comunità. Forse @GeorgeWS può chiarire perché cambiare gli argomenti switch e case funziona per il suo caso d'uso?
Slipp D. Thompson

2
Sono un po 'perso. qual è la differenza tra i tuoi primi due casi? someValue?è un altro valore definito, ma case let val?è solo la versione sicura da scartare di someOptional?!
Miele

@Honey Non è un esempio di codice del mondo reale; è semplicemente una variazione della risposta di Rintaro. Quindi fagli questa domanda: la mia risposta è funzionalmente equivalente al codice nella sua. Se dovessi chiedere a rintaro, però, credo che la risposta sarebbe 1. rispecchia quello che c'è nei documenti Apple collegati; 2. mostra solo la sintassi; non realizza un calcolo distinto o un obiettivo di logica aziendale.
Slipp D. Thompson

@Honey Inoltre, la risposta di rintaro è stata originariamente scritta per Swift 1.x e aggiornata per Swift 2. È possibile che la versione senza letnon venga più compilata. Non ricordo in questo momento perché avrebbe funzionato nel corso della giornata.
Slipp D. Thompson

10

In Swift 4 puoi usare Optional: ExpressibleByNilLiteral di Apple per wrapper facoltativo

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

Esempio

enum MyEnum {
    case normal
    case cool
}

alcuni

let myOptional: MyEnum? = MyEnum.normal

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

    case .none: 
    break

    default:
    break
}

nessuna

let myOptional: MyEnum? = nil

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

    case .none: 
    // Found nil
    break

    default:
    break
}

predefinito

let myOptional: MyEnum? = MyEnum.cool

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

    case .none: 
    break

    default:
    // Found .Cool enum
    break
}

Enum con valore

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

qualche valore

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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.