0

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

例如

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 中做到这一点?

4

3 回答 3

2

我只是将Sequence协议约束扩展ElementEquatable并实现一个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($0) } }

用法:

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]
于 2021-08-23T22:10:30.653 回答
1

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

可悲的是,你不能,因为这需要类型(Int) -> Bool有一个not方法。函数不能有方法。

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

我建议你这样写:

let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter { !digitsExceptForFive.contains($0) }
于 2021-08-23T21:14:31.783 回答
0

为了符合人体工程学语义,需要将这种语言支持添加到 Swift 中。请参阅Swift Evolution 论坛上的进化音调讨论

于 2021-09-01T14:31:36.310 回答