Swift: teste em relação ao valor opcional em caso de switch

89

Em Swift, como posso escrever um caso em uma instrução switch que testa o valor sendo alternado em relação ao conteúdo de um opcional , ignorando o caso se o opcional contiver nil?

Veja como eu imagino que isso seja:

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 eu apenas escrever exatamente assim, o compilador reclamará que someOptionalnão foi desembrulhado, mas se eu desembrulhar explicitamente adicionando !ao final, é claro que recebo um erro de tempo de execução sempre que someOptionalcontém nil. Adicionar em ?vez de !faria algum sentido para mim (no espírito do encadeamento opcional, eu suponho), mas não faz com que o erro do compilador desapareça (ou seja, não desembrulha o opcional).

George WS
fonte

Respostas:

112

Opcional é assim enum:

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

    // ...
}

Portanto, você pode combiná-los como os padrões de correspondência normais de "Valores associados" :

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 você quiser correspondência de someValue, usando a expressão de guarda :

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

E para Swift> 2.0

switch someValue {
case let val where val == someOptional:
    print("matched")
default:
    print("didn't match; default")        
}
Rintaro
fonte
4
Observe que no Swift 3, alguns / nenhum estão em minúsculas, ou seja, você usaria .some em vez de .Some
Adam
53

A partir do Xcode 7 (a partir das notas de lançamento do beta 1), “um novo x?padrão pode ser usado para combinar padrões com opcionais como sinônimo de .Some(x)”. Isso significa que no Xcode 7 e posterior, a seguinte variação da resposta de rintaro também funcionará:

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
fonte
3
A questão é sobre comparar um valor não opcional com um opcional, esta resposta é o contrário.
Martin R de
2
É verdade, no entanto, essa resposta foi originalmente escrita pelo OP como uma atualização da pergunta, portanto, para ele, era irrefutavelmente uma solução viável; Acabei de mudar para uma resposta do wiki da comunidade. Talvez @GeorgeWS possa esclarecer por que mudar os argumentos switch e case funciona para seu caso de uso?
Slipp D. Thompson de
2
Estou um pouco perdida. qual é a diferença entre seus dois primeiros casos? someValue?é algum outro valor definido, mas case let val?é apenas a versão segura e desembrulhada de someOptional?!
Mel
@Honey Não é um exemplo de código do mundo real; é simplesmente uma variação da resposta de rintaro. Então vá fazer essa pergunta a ele / ela - minha resposta é funcionalmente equivalente ao código dele / dela. Porém, se você perguntasse a rintaro, acredito que a resposta seria 1. ele reflete o que está nos documentos da Apple vinculados; 2. apenas demonstra a sintaxe; ele não atinge um cálculo distinto ou objetivo de lógica de negócios.
Slipp D. Thompson
@Honey Além disso, a resposta de rintaro foi escrita originalmente para Swift 1.xe atualizada para Swift 2. É possível que a versão sem letnão seja mais compilada. Não consigo me lembrar agora por que isso teria funcionado naquela época.
Slipp D. Thompson
10

No Swift 4, você pode usar Optional: ExpressibleByNilLiteral da Apple para empacotar opcional

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

Exemplo

enum MyEnum {
    case normal
    case cool
}

alguns

let myOptional: MyEnum? = MyEnum.normal

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

    case .none: 
    break

    default:
    break
}

Nenhum

let myOptional: MyEnum? = nil

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

    case .none: 
    // Found nil
    break

    default:
    break
}

padrão

let myOptional: MyEnum? = MyEnum.cool

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

    case .none: 
    break

    default:
    // Found .Cool enum
    break
}

Enum com valor

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

algum valor

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
fonte