
Swiftで「この2つの値は同じかどうか」を判定したい場面はとても多いですよね。
そんなときに欠かせないのが Equatableプロトコル です。
Equatableプロトコル を使うことで「2つの値が等しいかどうか」を判定できるようになります。
もしEquatableを使わなかったら、「同じ見た目のインスタンスなのに、等しいと判定できない」 という不便なことが起こりますが、初心者にはめちゃくちゃ理解しにくい、、、
私もアプリ開発始めて1年ぐらいは正直、
「Equatableプロトコルって何のために使うんだろう?エラーになるから入れているけど、、、」
という感じで全く理解できずになんとなく使っていました笑
この記事では、Equatableとは何か、どんな目的で使うのか、そして「使わなかったらどうなるのか?」をなるべくわかりやすくに解説していきます。
Equatableとは?
EquatableはSwift標準のプロトコルで、「2つの値が等しいかどうか」を判定できるようにするための仕組みです。
このプロトコルに準拠すると、== 演算子を使ってオブジェクト同士を比較できるようになります。
たとえば、配列の中に特定の要素が含まれているかを判定する contains や、要素のインデックスを調べる firstIndex(of:) なども、要素が Equatable に準拠していることが前提です。
このEquatableプロトコルを理解するためには、Equatableを使わない場合の具体例で考えるのがおすすめです。
Equatableを使わなかった場合の具体例
以下のような構造体 User を考えてみましょう。
|
1 2 3 4 5 6 7 8 |
struct User { let id: Int let name: String } let user1 = User(id: 1, name: "Taro") let user2 = User(id: 1, name: "Taro") |
上記コードの use1 と use2 の2つのインスタンスは、見た目はまったく同じですよね?
でも、この状態ではSwiftは「同じユーザーだ」とは判断してくれません。
試しに比較してみようとすると…
|
1 2 3 4 |
if user1 == user2 { print("同じユーザーです") } |
これはコンパイルエラーになります。
なぜなら、User が Equatable に準拠していないため、どのプロパティ(今回だとid やname)が同じなら等しいという基準がないからです。
例えば、id が同じなら「2つは等しい」とみなしてよい、とか、 idとname それぞれが一致する場合だけ「2つは等しい」という基準がないとSwiftは2つのインスタンスが等しい可動化の判定ができません。
同じように、配列の中に含まれているかを調べようとしても、Equatableを指定していないとエラーになります。
|
1 2 3 |
let users = [user1] print(users.contains(user2)) // エラー! |
このように、Equatableがないと「等しいかどうか」を判定する処理そのものが書けないのです。
Equatableを使うとどう変わる?
では、User に Equatable をつけてみましょう。
|
1 2 3 4 5 |
struct User: Equatable { let id: Int let name: String } |
たったこれだけです。
Swiftは自動で下記のような == の比較方法を合成してくれます(すべてのプロパティがEquatableならOK)。
|
1 2 3 4 |
static func == (lhs: User, rhs: User) -> Bool { return lhs.id == rhs.id && lhs.name == rhs.name } |
上記の意味は、「左側のidと右側のidが一致する」、かつ「左側のnameと右側のnameも一致する」であれば、Trueを返す、という意味です。
つまり、Swiftが「2つのインスタンスが等しい」と判断する基準を「idとnameどちらも一致すれば等しい」と設定してあげているのです。
この状態であれば、先ほどのコードはすべて正常に動作します。
|
1 2 3 4 5 6 7 |
if user1 == user2 { print("同じユーザーです") // これは出力されます } let users = [user1] print(users.contains(user2)) // true |
つまり、「プロパティが全部同じなら、等しいとみなす」という判断を、Swiftが自動でしてくれるのです。
プロパティの一部だけで比較したい場合
業務アプリなどでは「このIDが同じなら同一とみなす」といったケースもあります。
そんなときは == の定義を自分で書くこともできます。
|
1 2 3 4 5 6 7 8 9 10 |
struct Product: Equatable { let id: Int let name: String let price: Int static func == (lhs: Product, rhs: Product) -> Bool { return lhs.id == rhs.id } } |
このようにすれば、IDが同じなら等しい(nameの値が違っていたとしても)とSwiftが判断してくれるようになります。
このカスタマイズができるのもEquatableの大きなメリットです。
Equatableの主な活用場面
Equatableはとにかく様々なところで使われます。
特に多いのが下記のような場面です。
- 配列の中に特定の要素があるかを確認したいとき(contains)
- 2つの構造体インスタンスが同じ内容かを判定したいとき(==)
- SwiftUIの
onChange(of:)で状態の変化を検知したいとき - SwiftUIの
.equatable()で再描画の最適化をしたいとき - テストコードで、期待値と実際の値が一致するか確認したいとき
SwiftUIでの具体的な使い方例
SwiftUIでもEquatableは重要な役割を果たします。
例えば、 onChange を使って、値が変わったときに処理を行いたい場合の例です。
|
1 2 3 4 5 6 7 8 9 10 11 |
struct ContentView: View { @State private var name = "" var body: some View { TextField("名前を入力", text: $name) .onChange(of: name) { newValue in print("新しい値: \(newValue)") } } } |
ここで name は String(Equatable準拠)なので、前回のname と新しい値が違う場合だけクロージャが呼ばれます。
もしEquatableじゃなかったら、「値が変わったかどうか」が判定できず、このような便利な処理はできません。
Equatableを使うときの注意点
Equatable はとても便利ですが、いくつか知っておかないとつまずきやすいポイントがあります。
特に「どのプロパティを比較対象にするのか」は、アプリの設計に直結する大事な部分です。
1. 自動実装が効くのは「すべてのプロパティが Equatable な場合」だけ
構造体や列挙型のすべてのストアドプロパティが Equatable に準拠していれば、自動で == が生成されます。
逆に、プロパティの中に Equatable でない型(Any や クロージャ など)が含まれている場合は、自分で == を実装する必要があります。
2. class(参照型)では自動実装されない
struct や enum では便利な自動合成が使えますが、class(参照型)は違います。
クラスは インスタンスの参照そのものが同一かどうか を扱うため、== の比較基準を自分で定義する必要があります。
例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class User: Equatable { let id: Int let name: String init(id: Int, name: String) { self.id = id self.name = name } static func == (lhs: User, rhs: User) -> Bool { return lhs.id == rhs.id && lhs.name == rhs.name } } |
3. 等しいと判定する基準は用途に応じて設計する
単純に「すべてのプロパティが一致すれば等しい」とするのは便利ですが、必ずしも最適とは限りません。
- ユーザー管理 →
idが同じなら同じユーザーとみなす - 商品管理 →
productCodeが同じなら同じ商品とみなす
|
1 2 3 4 5 6 7 8 |
struct User: Equatable { let id: Int let name: String static func == (lhs: User, rhs: User) -> Bool { return lhs.id == rhs.id // name は無視 } } |
まとめ
Equatable は、Swift での開発に欠かせない基本プロトコルのひとつです。
最後にポイントを整理してみましょう。
- Equatableは、「値が等しいかどうか」を判定するためのプロトコル
- SwiftUIやテストなど、さまざまな場面で使われる超重要なプロトコル
- 構造体や列挙体では、プロパティがすべてEquatableなら自動で実装される
- Equatableがないと
==やcontainsなど、等価判定が一切できない - 自分で
==を定義することで、「どのプロパティが同じなら等しいか」をカスタマイズできる
Swiftでアプリを作るうえで、Equatableをうまく使うことはとても大事なスキルです。
「どんなときに等しいとみなすのか?」という考え方をしっかり身につけていきましょう。

