Swift:在切换情况下针对可选值进行测试


89

在斯威夫特,我怎么能写这样的情况,一个开关语句测试值被切换对抗的内容可选,跳过如果可选包含案例nil

这是我想象的样子:

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
}

如果我只是这样写,那么编译器会抱怨someOptional没有解包,但是如果我通过添加!到末尾来显式解包,那么我当然会在someOptional包含的任何时间得到运行时错误nil。添加?代替!对我来说是有意义的(我想是基于可选链接的精神),但不会使编译器错误消失(即,实际上并没有解开可选)。

Answers:


112

可选enum就像这样:

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

    // ...
}

因此,您可以像往常一样将它们与“关联值”匹配模式进行匹配:

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

如果要从匹配someValue,请使用保护表达式

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

对于Swift> 2.0

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

4
请注意,在Swift 3中,某些/无小写字母,即您将使用.some而不是.Some
Adam

53

从Xcode 7开始(来自beta 1发行说明),“ x?可以使用新模式来对可选内容进行模式匹配,作为。的同义词.Some(x)。” 这意味着在Xcode 7及更高版本中,林达罗答案的以下变体也将起作用:

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
问题是关于将非可选值与可选值进行匹配,反之亦然。
Martin R

2
是的,但是这个答案最初是由OP写的,是对问题的更新,因此对他来说,这无疑是一个可行的解决方案。我只是将其移至社区Wiki答案。也许@GeorgeWS可以弄清楚为什么切换switch&case args可以用于他的用例?
斯利普·汤普森

2
我有点迷路了。您的前两种情况有什么区别?someValue?是其他定义的值,但case let val?只是安全的展开版本someOptional
亲爱的

@Honey这不是真实的代码示例;这只是林太郎答案的一种变体。所以去问他/她这个问题-我的回答在功能上等同于他/她的代码。如果您要问林达罗,我相信答案是1.它反映了链接的Apple文档中的内容;2.它仅演示语法;它没有实现明确的计算或业务逻辑目标。
Slipp D. Thompson

@Honey另外,rintaro的答案最初是为Swift 1.x编写的,并针对Swift 2进行了更新。该版本可能let不再编译。我现在不记得为什么这在过去会奏效。
Slipp D. Thompson

10

Swift 4中,您可以使用Optional: Apple的ExpressibleByNilLiteral包装可选

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

enum MyEnum {
    case normal
    case cool
}

一些

let myOptional: MyEnum? = MyEnum.normal

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

    case .none: 
    break

    default:
    break
}

没有

let myOptional: MyEnum? = nil

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

    case .none: 
    // Found nil
    break

    default:
    break
}

默认

let myOptional: MyEnum? = MyEnum.cool

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

    case .none: 
    break

    default:
    // Found .Cool enum
    break
}

枚举值

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

一些价值

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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.