【Swift】Hashableプロトコルとは?使い方や使う目的、Equatableプロトコルとの違いまでわかりやすく解説!

Swiftでコレクション型(SetやDictionary)を使うときによく出てくるのが Hashableプロトコル です。

「Hashableって何?」「Equatableとどう違うの?」と思う方も多いかもしれません。

この記事では Hashableプロトコルの基本的な意味や使い方、どんな場面で使うのか、関連するプロトコルとの違い までをわかりやすく解説します。

Hashableとは?

HashableはSwift標準ライブラリのプロトコルで、オブジェクトを「ハッシュ値」という数値に変換できることを保証するもの です。

例えば、SetやDictionaryのキーは必ずHashableに準拠していなければいけません。

なぜなら、これらのコレクションは「同じ値かどうか」を高速に判定するために、ハッシュ値を使っているからです。

もしHashableがなかったら、Swiftはそのオブジェクトをどのように一意に区別すればいいかわかりません。

つまり:

  • Hashableに準拠 → コレクションの中で重複を避けられる
  • Hashableに準拠 → Dictionaryのキーとして使える

という役割を担っています。

具体例:Setで使ってみる

Swift で Set を使う際に重要なのが、要素が Hashable に準拠している必要があるという点です。

Hashable に準拠することで、Swift は要素を一意に識別できるようになり、重複を排除して効率的に管理できます。

次の例では、自作の構造体をHashable に準拠させて、Setの中で使っています。

ポイント

  • 同じidとnameを持つuser1とuser3は「同じもの」とみなされる
  • Setでは自動的に重複が排除され、要素は2つだけ残る
  • 内部的には hash(into:)== を使って比較している

もしHashableに準拠していなければ、この構造体をSetに入れることはできません。

具体例:Dictionaryのキーとして使う

Swift で Dictionary を使うとき、キーが一意に判別できることがとても重要です。

そのため、キーとなる型は必ず Hashable に準拠していなければなりません。

たとえば、商品ごとに在庫数を管理したい時、Product という構造体を Hashable にしておけば、そのまま Dictionary のキーとして利用できます。

ポイント

  • Product がHashableに準拠しているからこそキーとして利用可能
  • Hashableでなければ「どのProductがどの在庫数に対応しているか」を区別できない

このように Hashable は、Set の重複排除だけでなく、Dictionary のキー管理にも欠かせません。

Swift のコレクション型を効果的に使うための基盤となる概念なのです。

SwiftUIでの例

SwiftUIのListでもHashableはよく使われます。

ポイント解説

  • id: \.self を指定しているのは、各要素そのものを ID として使うという意味

  • StringHashable に準拠しているので、文字列の内容を使って一意に判定できる
    "Apple""Banana" は異なる要素として区別される

  • もし Hashable でなければ、SwiftUI は「どの要素がどのセルに対応するのか」を識別できないため、List を正しく描画できない

主要なメソッドと自動実装

Hashable に準拠するときに関わるメソッドは大きく2つあります。

メソッド 役割
func hash(into hasher: inout Hasher) ハッシュ値を計算する
static func == (lhs: Self, rhs: Self) -> Bool Equatable 由来、等価判定

Swift では、すべてのストアドプロパティが Hashable に準拠していれば、これらのメソッドは自動的に実装されます。

自動実装の仕組み

Swift では、すべてのストアドプロパティが Hashable に準拠していれば、コンパイラがこれらのメソッドを自動で合成してくれます。

  • == は「すべてのプロパティが等しいかどうか」を比較するコードが自動生成される
  • hash(into:) は「すべてのプロパティのハッシュ値を組み合わせる」コードが自動生成される

つまり、開発者が特別なルールを設けない限り、structenum に単に Hashable と書くだけで十分です。

なぜ自動生成してくれるのか?

Swift が自動実装を提供するのは、よくある「全プロパティでの比較・ハッシュ化」パターンを簡単に扱えるようにするためです。

もし自動生成がなかったら、次のように毎回自分で書く必要があります:

これでは定型で書く必要があるコードが多くなってしまいます。

そのため Swift は 「すべてのプロパティを使う標準的な比較とハッシュ化」 を自動的に提供してくれるのです。

Equatable プロトコルとの違い

Hashable を理解する上で、まず比較されるのが Equatable です。

両者の違いをしっかり整理すると、なぜ HashableEquatable が含まれているのかがよくわかります。

Equatable とは?

Equatable は「この型のインスタンス同士を == で比較できること」を保証するプロトコルです。

ここで Equatable が保証しているのは:

  • 「==」という演算子が使えること
  • 2つのインスタンスが「等しい」かどうかを判定するルールを持っていること

「== で比較できるかどうかを保証」というのはつまり、その型に「等しい」「等しくない」を判定する基準を持たせるという意味です。

例えば、idname がどちらも一致すれば同じであれば、「等しい」、nameは一緒だけど、idが異なる場合は「等しくない」と判定する基準を持たせるということ。

もし Equatable に準拠していなければ、== を使ってその型を比較することがそもそもできません。

Hashable とは?

HashableEquatable を含みつつ、さらに 「インスタンスの内容を数値(ハッシュ値)に変換できる」 ことを保証するプロトコルです。

両者の関係

  • Equatable:インスタンス同士を 等しいかどうか判定できる
  • Hashable:インスタンス同士を 等しいかどうか判定できるハッシュ値で一意に識別できる

重要なのは、Hashable に準拠すると自動的に Equatable にも準拠する点です。

活用シーン

Hashable は、データを一意に区別したいときや、効率的に検索・比較したいときに欠かせないプロトコルです。

  • Setで重複を避けながらデータを管理したいとき
  • Dictionaryのキーに自作の型を使いたいとき
  • SwiftUIでListを作るときに id: \.self を使う場合(自己Hashableが必要)
  • データの一意性を保証したいとき

    注意点

    とても便利な Hashable ですが、使う際にはいくつかの注意点があります。

    これを理解しておかないと、思わぬバグや挙動不審の原因になりかねません。

    • ハッシュ値は一意性を完全に保証するものではない
      (異なる値が同じハッシュ値を持つ「衝突」が起こる可能性がある。ただし Swift のコレクションは内部で安全に処理している)

    • Hashable に準拠すると自動で Equatable にもなる
      (つまり == を使った比較も可能になる)

    • プロパティに非 Hashable 型が含まれる場合、自動で Hashable にはできない
      (その場合は手動で hash(into:)== を実装する必要がある)

    • SwiftUI の id: \.self は便利だが注意が必要
      (値そのものを ID にしているため、同じ値が複数あると区別できない。また値が変わると別の要素とみなされ、セルが再生成されることもある)

    まとめ

    今回は Swift の Hashable プロトコルについて解説しました。

    • Hashableは「オブジェクトをハッシュ値に変換できること」を保証するプロトコル
    • SetやDictionaryでの重複判定やキー利用に必須
    • Equatableプロトコルを内包しているため、比較も可能
    • SwiftUIのListなど、UI周りでもよく使われる

    初心者がまず理解すべきポイントは 「SetとDictionaryで使うための仕組み」 です。

    慣れてきたら hash(into:) をカスタマイズして、さらに理解を深めていきましょう!

    おすすめの記事