检查字符串是否包含 Swift 中的可选字符串,但前提是它不是 nil



我想添加一个可选的"过滤器";处理字符串列表的函数的参数。如果过滤器是nil,我想处理所有的字符串,否则我只想处理包含过滤器的字符串。大致:

func process(items: [String], filter: String?) {
for item in items {
if filter == nil || item.contains(filter) {
// Do something with item
}
}
}

类型检查器抱怨将筛选器传递到contains,因为它是可选的,但contains需要String。我当然可以强行打开包装,但这看起来很难看。以上内容将在Kotlin中编译,因为它会明智地丢弃可选内容,但在Swift中表达这一点的惯用方式是什么?

谢谢!

Optional上有一个map,它仅在可选不是nil时执行所提供的闭包。如果map返回nil,则可以将mapnil合并运算符??一起使用以提供true的默认值,因为filternil:

func process(items: [String], filter: String?) {
for item in items {
if filter.map(item.contains) ?? true {
// process item
}
}
}

这里的关键是(并且一直是(nil合并运算符。如果Optional不是nil,则可以安全地打开它,但如果nil,则可以替换另一个值。

然而,这个问题的问题在于,它摆出了一种不敏捷的姿态。您永远不会编写一个采用可选字符串的过滤函数。您将编写一个过滤函数,该函数采用Optional过滤函数您希望允许任何类型的数组和任意过滤函数,而不是将调用方限制为contains和String。这是编写此函数的快捷方式。

当我们处理它时,函数也不应该预先确定对数组成员执行的操作。这应该是调用方传入的另一个函数!

因此,我们最终得出了一个更一般、更Swiftier的目标声明:

func process<T>(_ arr: [T],
filtering filterPred: ((T)->Bool)? = nil,
processing processPred: ((T)->Void)) {
// ...
}

好吧!让我们来写这个函数。processing部分很简单;这是CCD_ 18调用的谓词。像这样:

func process<T>(_ arr: [T],
filtering filterPred: ((T)->Bool)? = nil,
processing processPred: ((T)->Void)) {
arr.forEach(processPred)
}

非常好!但我们忽略了对CCD_ 19函数的处理。让我们来处理这个问题。显然,这是橡胶与道路交汇的地方。同样显而易见的是,这是一个要传递到filter中的函数。但只有当它不是nil时,我们才能通过展开来做到这一点。如果nil怎么办?OP已经指定,在这种情况下,我们应该让所有元素通过过滤器。

因此,考虑一个要传递到filter中的谓词函数。是什么让一切都通过的函数?它是:

{ _ in true }

所以就是要放在零合并运算符后面的!因此,这就是完整的答案:

func process<T>(_ arr: [T],
filtering filterPred: ((T)->Bool)? = nil,
processing processPred: ((T)->Void)) {
arr.filter(filterPred ?? { _ in true }).forEach(processPred)
}

这里有两个测试:

let arr = [1,2,3,4]
self.process(arr) { print($0) }
self.process(arr) { $0 % 2 == 0 } processing: { print($0) }

相关内容

最新更新