【问题标题】:Swift: testing against optional value in switch caseSwift:在 switch case 中针对可选值进行测试
【发布时间】:2015-01-12 12:36:46
【问题描述】:

在 Swift 中,我如何在 switch 语句中编写一个 case 来测试被切换的值与 optional 的内容,如果 optional 包含 nil 则跳过 case? p>

这是我想象中的样子:

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。添加? 而不是! 对我来说是有意义的(本着可选链接的精神,我想),但不会使编译器错误消失(即实际上并没有解开可选)。

【问题讨论】:

    标签: swift enums switch-statement optional


    【解决方案1】:

    可选的只是一个enum,像这样:

    enum Optional<T> : Reflectable, NilLiteralConvertible {
        case none
        case some(T)
    
        // ...
    }
    

    所以你可以像往常一样匹配它们"Associated Values"匹配模式:

    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,使用guard expression

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

    【讨论】:

      【解决方案2】:

      从 Xcode 7 开始,“一个新的 x? 模式可用于模式匹配作为 .some(x) 的同义词的可选项”。 这意味着在 Swift 2 及更高版本中,以下变体的rintaro's answer 也可以:

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

      【讨论】:

      • 问题是关于将非可选值与可选值匹配,这个答案是相反的。
      • 是的,但是这个答案最初是由 OP 编写的,作为对问题的更新,所以对他来说,这无疑是一个可行的解决方案;我只是将其移至社区 wiki 答案。也许@GeorgeWS 可以澄清为什么切换开关和案例参数适用于他的用例?
      • 我有点迷路了。你的前两个案例有什么区别? someValue? 是其他定义的值,但 case let val? 只是 someOptional 的安全解包版本?!
      • @Honey 这不是真实世界的代码示例;这只是 rintaro 答案的变体。所以去问他/她这个问题——我的答案在功能上等同于他/她的代码。不过,如果您要问 rintaro,我相信答案是 1。它反映了链接的 Apple 文档中的内容; 2. 只演示语法;它没有完成不同的计算或业务逻辑目标。
      • @Honey 另外,rintaro 的答案最初是为 Swift 1.x 编写的,并为 Swift 2 更新。没有let 的版本可能不再编译。我现在不记得为什么那会在过去起作用。
      【解决方案3】:

      Swift 4 中,您可以使用 Apple 的 Optional : 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
      }
      

      【讨论】:

      • 您提到ExpressibleByNilLiteral,但实际上并没有在枚举声明等中使用。那是什么?
      【解决方案4】:

      您可以明确提及所有情况以及nil 作为处理可选情况的附加情况:

      switch optionalEnumValue {
      case .caseOne:
          break
      case .caseTwo:
          break
      case .caseN:
          break
      case nil:
          break
      }
      

      【讨论】:

        猜你喜欢
        • 2020-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多