Swift中for循环中的模式匹配

5
似乎应该有一种更快捷的方式来完成这个任务——但是我还在努力理解Swift中各种模式匹配的方法。
假设我有一个AnyObject类型的数组,我想遍历它,如果其中的项是Int类型并且是5的倍数,则我想打印出它。以下是我的初始方法:
```swift for item in array { if let number = item as? Int { if number % 5 == 0 { print(number) } } } ```
let myStuff: [AnyObject] = [5, "dog", 11, 15, "cat"]

for item in myStuff {
    if let myInt = item as? Int where myInt % 5 == 0 {
        print ("\(item)")
    }
}

说实话,这并不差……但是考虑到Swift的所有模式匹配语法,我应该能够将逻辑整合为一行。到目前为止,我还没有找到可行的方法——但我本来希望能够做到像下面这样的事情:
//This doesn't work, but I feel like something similar to this should
for item in myStuff where item is Int, item % 5 == 0 {
    print ("\(item)")
}

显然,这不是一个很大的问题 - 但对我来说更像是一个思维练习,以更好地理解Swift的模式匹配。
2个回答

13

你可以使用模式匹配条件强制转换where子句结合使用,如下所示:

let myStuff: [AnyObject] = [5, "dog", 11, 15, "cat"]

// item will be an Int, and divisible by 5
for case let item as Int in myStuff where item % 5 == 0 {
    print(item)
}

// Prints:
// 5
// 15

啊!我在尝试中接近了。我实际上尝试过:"case let item as? Int..."。这让我感觉很正确,因为if语句的语法是:"if let item = something as? Int...."。 - chrismc
@chrismc 是的,使用可选绑定进行条件转换的语法(if let ... as? ...)与使用模式匹配进行条件转换的语法确实不同。你实际上可以将该 if 语句重写为 if case let item as Int = something,尽管这显然比 if let item = something as? Int(因此很少见)表达力更弱。它们之所以不同是因为 as? 生成一个可选项,而可选绑定然后取消包装 - 但是 as 类型转换模式只是尝试进行类型转换,并在成功时匹配。 - Hamish

7

@Hamish的巧妙解决方案在我看来是最“优化”的一个,也应该被接受。但为了讨论的缘故,作为替代方案,可以使用链式函数方法应用略有不同的逻辑:

let myStuff: [AnyObject] = [5, "dog", 11, 15, "cat"]

myStuff.flatMap{ $0 as? Int }.filter{ $0 % 5 == 0}.forEach {
    print($0)
} /* 5 15 */

1
没问题 @dfri :) - Hamish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接