Swift: 在功能上使用 not 运算符

Swift: use not operator functionally

我想使用点语法得到布尔值的相反值。

例如

let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(!digitsExceptForFive.contains)
// Cannot convert value of type '(Int) -> Bool' to expected argument type 'Bool'

但是,以下代码有效。

let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let notFives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(digitsExceptForFive.contains)
// [1, 2, 3, 4, 6, 7, 8, 9]

我需要使用 not 运算符在功能上获得相反的值。如果可能的话,我不想为此定义布尔扩展或自定义运算符。

如何在 Swift 中做到这一点?

我猜你想写类似 digitsExceptForFive.contains.not 的东西。

遗憾的是,您不能,因为这需要类型 (Int) -> Bool 具有 not 方法。函数不能有方法。

您可以编写运算符 ! 的重载来执行此操作(让您的第一次尝试成功),但我不推荐这样做。运算符重载往往会减慢编译时间并使后来的代码读者感到困惑。

我建议你这样写:

let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter { !digitsExceptForFive.contains([=10=]) }

我只想将 Sequence 协议约束 Element 扩展到 Equatable 并实施 notContains 方法:

extension Sequence where Element: Equatable {
    func notContains(_ element: Element) -> Bool { !contains(element) }
}

let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(digitsExceptForFive.notContains)  // [5]

您还可以扩展 Bool and 提供 negated 属性,这将允许使用否定的 KeyPath 语法:

extension Bool {
    var negated: Bool { !self }
}

let string = "abc12345" 
let nonDigits = string.filter(\.isWholeNumber.negated) // "abc"

如果你真的想实现自定义前缀运算符(我真的更喜欢使用 notConstains 方法和 Bool 否定实例 属性)你可以这样做:

prefix func !<T>(predicate: @escaping (T) -> Bool) -> (T) -> Bool { { !predicate([=14=]) } }

用法:

let string = "abc12345"
let nonDigits = string.filter(!\.isWholeNumber) // "abc"

let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(!digitsExceptForFive.contains) // [5]

需要将此语言支持添加到 Swift 以符合人体工程学语义。请参考evolution pitch discussion on the Swift Evolution forums.