【问题标题】:Swift switch pattern matching with arrays与数组匹配的 Swift 开关模式
【发布时间】:2016-12-08 02:25:53
【问题描述】:

很好奇是否有办法在 Swift 中执行以下操作。

let foo = [1, 2, 3]
let bar = [4, 5, 6]

let value = 5

switch value {
case in foo
    print("5 is in foo")
case in bar
    print("5 is in bar")
default:
    break
}

我知道还有其他方法可以使这个人为的示例工作,例如case 4, 5, 6: 或不使用开关,而是使用bar.contains(value),但我正在寻找一种解决方案,专门涉及与数组匹配的开关模式。谢谢!

【问题讨论】:

    标签: ios arrays swift switch-statement


    【解决方案1】:

    @Martin R 为什么要停在数组上。所有符合Sequence 协议的类型都有一个contains 实例方法。以下内容与您的答案具有相同的行为,但它适用于符合 Sequence 的任何类型。

    func ~=<S : Sequence>(sequence: S, value: S.Element) -> Bool
            where S.Element: Equatable {
    
        return sequence.contains(value)
    }
    
    
    let items = [1, 2, 3, 4, 5]
    let iterable = items.makeIterator()
    
    let value = 3
    
    switch value {
        case iterable:
            print("\(value) is contained in iterable")
        default:
            print("\(value) is NOT contained in iterable")
    }
    

    但是,我们可以做得更好

    我觉得case iterable 太神奇了。它没有传达我们正在测试valueiterable 中的成员身份的事实。如果我们可以写case containedIn(iterable) 会更好。事实上,这实际上是可能的:

    public func ~=<T>(pattern: (T) -> Bool, value: T) -> Bool {
        return pattern(value)
    }
    
    func containedIn<S : Sequence>(_ sequence: S) -> ((S.Element) -> Bool)
            where S.Element: Equatable {
    
        return { element in sequence.contains(element) }
    }
    
    let arrayOfNumbers = [1, 2, 3, 4, 5]
    let setOfNumbers: Set = [5, 6, 7, 8, 9, 10]
    
    let value = 8
    
    switch value {
        case containedIn(arrayOfNumbers):
            print("\(value) is contained in arrayOfNumbers")
        case containedIn(setOfNumbers):
            print("\(value) is contained in setOfNumbers")
        default:
            break
    }
    

    唯一的问题是containedIn 在 switch 语句的上下文之外使用时会出现意外行为。

    【讨论】:

      【解决方案2】:

      您可以定义自定义模式匹配运算符 ~= 将数组作为“模式”和一个值:

      func ~=<T : Equatable>(array: [T], value: T) -> Bool {
          return array.contains(value)
      }
      
      let foo = [1, 2, 3]
      let bar = [4, 5, 6]
      
      let value = 5
      
      switch value {
      case foo:
          print("\(value) is in foo")
      case bar:
          print("\(value) is in bar")
      default:
          break
      }
      

      类似的运算符已经存在,例如对于间隔:

      public func ~=<I : IntervalType>(pattern: I, value: I.Bound) -> Bool
      

      【讨论】:

      • 不错。希望我能想到这一点。
      【解决方案3】:

      怎么样:

      let foo = [1, 2, 3]
      let bar = [4, 5, 6]
      
      let value = 5
      
      switch value {
      case _ where foo.contains(value):
          print("\(value) is in foo")
      case _ where bar.contains(value):
          print("\(value) is in bar")
      default:
          print("\(value) is not in foo or bar")
      }
      

      【讨论】:

      • 我认为这个解决方案比公认的答案更容易理解。谢谢! :)
      • 这个也比接受的答案更安全。谢谢。
      • @Vitalii 您认为接受的答案不太“安全”?
      猜你喜欢
      • 2010-09-17
      • 2017-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多