CompalableとEqutable

Swiftには構造体やクラスどうしの比較を行いたい時に使うと便利なProtocolが用意されています。

Equtable

Equtableがない場合

Yasaiという構造体を例にEqutableの使い方を確認していきます。

struct Yasai {
    var icon: String
    var value: Int
}

野菜のインスタンスがいくつか存在し、それらの野菜が一致するかしないかを判定したい時どのようにすれば良いでしょうか?

let tomato = Yasai(icon: "🍅", value: 100)
let nasu = Yasai(icon: "🍆", value: 80)

if tomato == nasu {
    print("同じ野菜だよ")
} else {
    print("違う野菜だよ")
}

🍅と🍆のインスタンスを作成して比較してみました。

これで判定が行えるのであれば良いのですが、ビルドしようとするとコンパイラに怒られてします。Yasai型には==という演算子を使用することができないと言っています。

Equtableに準拠する

struct Yasai: Equatable {
    var icon: String
    var value: Int
}

Equtableに準拠した場合==の演算子を使うことができるようになります。

先ほどのプログラムをビルドすると以下のような結果になりました。

==の条件をカスタマイズする

一致させる条件は独自にカスタマイズすることが可能です。

今回例に使用したYasaiですが、同じ🍆でも値段が異なることがあります値段が違っても🍆であることは変わりないので一致させたい場合は以下のようにYasaiの中にメソッドを追加します

struct Yasai: Equatable {
    var icon: String
    var value: Int
    
    static func == (lhs: Yasai, rhs: Yasai) -> Bool{
       return lhs.icon == rhs.icon
    }
}

プログラムを作り替えたて高級な🍆350円と、普通の🍆80円を比較してみました!

すると以下のように同じ野菜であるということを判定することができました。

Comparable

Equtableに準拠することで同じ野菜であるかの判定はすることになりました。では次に価格の比較を行いたい場合はどうすれば良いでしょう?

何も考えずに🍆どうしを比較してみました。

すると、>演算子は使えないとコンパイラに怒られてしまいました。

Comparableに準拠する

YasaiにComparableを準拠させてみます。Equtableの時は定義しない場合完全一致かそうでないかの判定を勝手に作ってくれていましたが、Comparableは比較対象を明示的に宣言してあげる必要があります。

struct Yasai: Equatable, Comparable {
    
    var icon: String
    var value: Int
    
    static func < (lhs: Yasai, rhs: Yasai) -> Bool {
        return lhs.value < rhs.value
    }
    
    static func == (lhs: Yasai, rhs: Yasai) -> Bool{
        return lhs.icon == rhs.icon
    }
}

先ほどのプログラムを実行してみると、以下のように高級🍆のほうが値段が高いことを判定することができました!

参考文献

Swift の Comparable プロトコルを基礎から

Swift の Equatable プロトコルを基礎から