Swift 在协议上具有可比性

Swift comparable on a protocol

大家新年快乐

protocol Birthday {
    var date: Date { get set }
}
    
class Person: Birthday {
    var date: Date
    var fullName: String

    // ...
}

class Car: Birthday {
    var date: Date
    var color: UIColor

    // ...
}

我希望它符合Comparable,所以我可以做到

Person() > Car()

而不是

Person().date > Car().date

我该怎么做?非常感谢

您可以> 轻松完成。只需编写以下顶层函数:

func > (lhs: Birthday, rhs: Birthday) -> Bool { lhs.date > rhs.date }

但是你不能让 Birthday 符合 Comparable。 Comparable 要求类型实现以下内容:

static func < (lhs: Self, rhs: Self) -> Bool

Self是符合协议的类型。协议不符合自身。它们不是“类型”。他们描述类型。 (在某些情况下,可能会生成隐式存在类型,但存在类型不能在 Swift 中进行操作。)要具有可比性,一个类型必须能够将自己与另一个 相同的事物进行比较输入,你无法通过协议获得它。

但是您可以创建任何您希望在协议中使用的特定语法。你只需要编写函数。

虽然这里有一个技术限制(协议不符合自身),即使 Swift 语法可以支持符合自身的协议(并且将来有办法),你仍然永远不应该以这种方式实现 Comparable。 Comparable 需要 Equatable。一个人永远不能等同于一辆汽车。那是因为 Equatable 需要的不仅仅是 == 函数。它需要可替代性。如果两件事在 Equatable 意义上“相等”,那么系统可以总是 用一个代替另一个,你永远不会关心它给你哪个。人和车就不是这样了。

为避免此类问题,不建议在此处使用<。这意味着这些东西只有一种合理的顺序,而“生日”并不是这些东西的唯一顺序。因此,如果您想比较日期,我肯定会建议您明确并比较日期。

感谢@Rob Napier 的精彩回答。

我想补充一些东西 - 对于那些想要符合 Comparable 以便能够对数组进行排序的人,我写了这个扩展:

extension Array where Element: Birthday {
    mutating func sort() {
        sort(by: { [=10=].date < .date })
    }
    
    func sorted() -> [Element] {
        return sorted(by: { [=10=].date < .date })
    }
}