【Swift】Hashable, Identifiableについて

## はじめに
HashableプロトコルとIdentifiableプロトコルって何のために使うの？違いは？と疑問に思ったので調べました。
もし間違いがありましたらご指摘いただけると幸いです。

## Hashable
### 概要
その型の値を元にハッシュ値が計算可能であることを表します。
下記のHashableの定義から、Hashableは`Equatable`プロトコルを準拠しており、`hashValue`プロパティと`hash`メソッドを持っていることがわかります。

```swift:Hashable
public protocol Hashable : Equatable {

    /// The hash value.
    ///
    /// Hash values are not guaranteed to be equal across different executions of
    /// your program. Do not save hash values to use during a future execution.
    ///
    /// - Important: `hashValue` is deprecated as a `Hashable` requirement. To
    ///   conform to `Hashable`, implement the `hash(into:)` requirement instead.
    var hashValue: Int { get }

    /// Hashes the essential components of this value by feeding them into the
    /// given hasher.
    ///
    /// Implement this method to conform to the `Hashable` protocol. The
    /// components used for hashing must be the same as the components compared
    /// in your type's `==` operator implementation. Call `hasher.combine(_:)`
    /// with each of these components.
    ///
    /// - Important: Never call `finalize()` on `hasher`. Doing so may become a
    ///   compile-time error in the future.
    ///
    /// - Parameter hasher: The hasher to use when combining the components
    ///   of this instance.
    func hash(into hasher: inout Hasher)
}
```

### Hashableへの準拠が必要なケース
ハッシュ値を用いて表現されるデータ構造において、Hashableに準拠された型の利用が必要になります。
代表的な一例ですが、Set、Dictionaryなどを利用する場合、Hashableに準拠した型が必須です。

#### Set
Setの定義を見ると、`Element : Hashable`となっており、Hashableに準拠しなければいけないことがわかります。

```swift:Setの定義
@frozen public struct Set<Element> where Element : Hashable
```

そのため、Hashableに準拠していないインスタンスをSetに利用すると、エラーが発生します。

```swift
struct GridPoint {
    var x: Int
    var y: Int
}

var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]
```

```:エラー内容
Generic struct 'Set' requires that 'GridPoint' conform to 'Hashable'
```

Hashableに準拠することでエラーが解消され、Setに利用できるようになります。

```swift
struct GridPoint: Hashable {
    var x: Int
    var y: Int
}

var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]

```

#### Dictionaryのキー
Setと同様に、Dictionaryの定義から `Key : Hashable` キーがHashableに準拠する必要があることがわかります。

```swift:Dictionaryの定義
@frozen public struct Dictionary<Key, Value> where Key : Hashable
```

そのため、Hashableに準拠していないインスタンスをDictionaryのキーに利用すると、エラーが発生します。

```swift
struct GridPoint {
    var x: Int
    var y: Int
}

let dictionary = [GridPoint(x: 2, y: 3): "point A", GridPoint(x: 4, y:1): "point B"]
```

```:エラー内容
Generic struct 'Dictionary' requires that 'GridPoint' conform to 'Hashable'
```


Hashableに準拠することでエラーが解消され、Setに利用できるようになります。

```swift
struct GridPoint: Hashable {
    var x: Int
    var y: Int
}

let dictionary = [GridPoint(x: 2, y: 3): "point A", GridPoint(x: 4, y:1): "point B"]
```

#### ForEach
SetやDictionaryと同様に、ForEachの定義から `ID : Hashable` IDがHashableに準拠する必要があることがわかります。

```swift:ForEachの定義
public struct ForEach<Data, ID, Content> where Data : RandomAccessCollection, ID : Hashable
```

Set、Dictionaryと同じなので、Hashableに準拠しない（エラーになる）場合の記載は割愛します。
以下のようにForEachのidには、Hahsableへの準拠が必要になります。

```swift:
struct GridPoint: Hashable {
    var x: Int
    var y: Int
}

struct ContentView: View {
    let array = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y:1)]

    var body: some View {
        List {
            ForEach(array, id: \.self, content: { elem in
                Text("x:\(elem.x) y:\(elem.y)")
            })
        }
    }
}
```

ForEachの場合、`Identifiable`を準拠するケースもよくあるので、そちらについては次節で説明します。

## Identifiable
### 概要
インスタンスが一意のIDを持つエンティティの値を保持するタイプのクラス。
下記のIdentifiableの定義を見ると、IDが`Hashable`を準拠していることがわかります。

```swift:Identifiable
public protocol Identifiable {

    /// A type representing the stable identity of the entity associated with
    /// an instance.
    associatedtype ID : Hashable

    /// The stable identity of the entity associated with this instance.
    var id: Self.ID { get }
}
```

また、Identifiableを準拠すると、そのクラスや構造体は`id`プロパティを持つ必要があります。

```swift
struct GridPoint: Identifiable {
    let id = UUID()
    var x: Int
    var y: Int
}
```

### Identifiableへの準拠が必要なケース
Hashableと似ていますが、一意に特定する必要がある要素において、Identifiableに準拠された型の利用が必要となるケースが多いです。
たくさんあるので、一例としてHashableでも出てきた`ForEach`について説明します。

#### ForEach

Hashableの例ではForEach内でidを引数指定していましたが、Identifiableを準拠したクラスや構造体の場合、そのクラスや構造体のプロパティにidがあるため、ForEach内では指定しません。

Hashableの場合
`ForEach(array, id: \.self, content: { elem in`

Identifiableの場合
`ForEach(array, content: { elem in`

ただ、今までと同様にIdentifiableを準拠していない場合、idが無いため、ForEachでエラーとなります。

```swift
struct GridPoint {
    var x: Int
    var y: Int
}

struct ContentView: View {
    let array = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y:1)]

    var body: some View {
        List {
            ForEach(array, content: { elem in
                Text("x:\(elem.x) y:\(elem.y)")
            })
        }
    }
}
```

なぜかこんなエラーが出ます。

> Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project

Identifiableを準拠することでエラーが解消され、ForEachで利用できるようになります。

```swift
struct GridPoint: Identifiable {
    let id = UUID()
    var x: Int
    var y: Int
}

struct ContentView: View {
    let array = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y:1)]

    var body: some View {
        List {
            ForEach(array, content: { elem in
                Text("x:\(elem.x) y:\(elem.y)")
            })
        }
    }
}
```

## Identifiable と Hashable の違い
では、IdentifiableとHashableの違いは何でしょうか？
こちらの記事によると、違いは以下のようです。
https://nshipster.com/identifiable/

* 識別子とは異なり、ハッシュ値は状態に依存し、オブジェクトが変更されると変化する。
* 識別子は起動間で安定しているが、ハッシュ値はランダムに生成されたハッシュシードによって計算されるため、起動間で不安定になる。
* 識別子は一意だが、ハッシュ値が衝突する可能性があるため、コレクションからフェッチするときに等価性チェックが必要になる。
* 識別子は意味のあるものになる可能性があるが、ハッシュ値は無秩序である。

つまりIdentifyとHashの言葉通り、識別子 ≠ ハッシュ値 となります。

## 最後に
普段何気なく利用していましたが、調べることで理解が深まり、意図を持って利用できるようになりました。
今後も疑問を持ったものは調べてまとめていければと思います。
閲覧いただきありがとうございました。