如何实现Swift的Comparable协议?

38

在Swift中如何使用Comparable协议?在声明中,它说我必须实现三个操作 <、<= 和 >=。我把所有这些都放在类里面,但还是行不通。另外,我需要同时拥有这三个操作吗?因为只要有其中一个,其他的就可以推断出来。

3个回答

67

可比较协议扩展了可等价协议 -> 要实现它们两个。

苹果参考文献中有一个来自苹果的例子(在Comparable协议参考中),你可以看到如何做:不要将操作实现放在类内部,而是放在外部/全局范围。另外,你只需要实现Comparable协议的<运算符和Equatable协议的==运算符。

正确的示例:

class Person : Comparable {
    let name : String

    init(name : String) {
        self.name = name
    }
}

func < (lhs: Person, rhs: Person) -> Bool {
    return lhs.name < rhs.name
}

func == (lhs: Person, rhs: Person) -> Bool {
    return lhs.name == rhs.name
}

let paul = Person(name: "Paul")
let otherPaul = Person(name: "Paul")
let ben = Person(name: "Ben")

paul > otherPaul  // false
paul <= ben       // false
paul == otherPaul // true

4
我不理解为什么这被认为是“已实现”,而实际的代码根本不在类中... == <和其他所有内容不应该在类内部吗?但是当我尝试这样做时,会出现错误.. 你知道我没有理解的是什么吗? - fjlksahfob
5
@fjlksahfob 的原因是因为它在类外部的作用域添加了运算符扩展。如果你愿意,甚至可以这样做:func == (lhs: ClassA, rhs: ClassB) -> Bool,以比较两个不同的类(测试显示只能按指定方向工作,所以你还必须创建 func == (lhs: ClassB, rhs: ClassA) -> Bool)。换句话说,Swift 编译器将 (X == Y) 解释为 ==(X, Y) 而不是 X.==(Y) - Oliver
@paulpaul1076 肯定不是 Swift 第一个,比如 Haskell,它也对 Swift 产生了很大的影响。不过我理解你的意思,自定义运算符重载确实非常好用 :D - Kametrixom
1
@Kametrixom,哦,很酷,我没有使用过Haskell,所以我不知道,谢谢你启发我。C#确实有自定义运算符重载,但是对于排序,您可以使用IComparable接口,并通过执行a.CompareTo(b) < 0进行比较,这意味着a < b。为什么不让IComparable具有<运算符呢?那就是我的观点。Swift看起来不错。 - Pavel
1
在Swift 5中,我发现当符合Comparable协议时,我不需要符合Equatable协议或实现==。我只实现了<,仍然能够测试相等性。这是因为聪明地重用了带有交换参数的<吗? - Barry Jones
显示剩余4条评论

7

以下是 Kametrixom 对于 Swift 3 的更新回答:

class Person : Comparable {

    let name : String

    init(name : String) {
        self.name = name
    }    

    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.name < rhs.name
    }

    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

可以使用以下关系运算符比较Person类的实例:

let paul = Person(name: "Paul")
let otherPaul = Person(name: "Paul")
let ben = Person(name: "Ben")

print(paul > otherPaul)  // false
print(paul <= ben)       // false
print(paul == otherPaul) // true

0
要实现Swift的Comparable协议,您需要先遵循Equatable协议,通过实现static func == (lhs: Self, rhs: Self) -> Bool,然后再实现Comparable所需的唯一函数static func < (lhs: Self, rhs: Self) -> Bool
与其声明全局运算符重载,不如在结构体/类本身中实现协议符合方法。虽然全局运算符重载满足协议符合性,但这种方式声明它们而不是结构体/类上预期的静态方法是不好的做法。
如果您查看文档示例,您将看到相同的内容作为示例代码显示。
我会写以下内容:
class Person: Comparable {
    let name: String

    init(name: String) {
        self.name = name
    }

    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.name < rhs.name
    }

    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

或者甚至将协议遵循从类声明中分离出来,像这样:

class Person {
    let name: String

    init(name: String) {
        self.name = name
    }
}

extension Person: Comparable {
    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.name < rhs.name
    }

    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

这可能更接近于生产级别的代码。


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