0Pricing
Swift Academy · レッスン

Hashableとhash(into:)

DictionaryのキーやSetの要素として使えるようにします。

「Hashableとhash(into:)」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。

Hashableとは

HashableはEquatableを拡張し、ハッシュ値を提供します。型をSetの要素やDictionaryのキーとして使用するには、Hashableへの準拠が必要です。

Hashableの自動生成

Equatableと同様に、Hashableのメンバーを持つ構造体と列挙型では、Hashableが自動生成されます。

struct Point: Hashable {
    let x: Int
    let y: Int
}
let set: Set<Point> = [Point(x: 0, y: 0), Point(x: 0, y: 0)]
print(set.count)  // 1  -- duplicate collapsed

型をDictionaryのキーとして使う

Hashableな型は、辞書のキーとして使用できます。

struct Coord: Hashable { let r: Int; let c: Int }
var grid: [Coord: String] = [:]
grid[Coord(r: 0, c: 0)] = "start"
print(grid[Coord(r: 0, c: 0)]!)  // "start"

Hashableの契約

等しい2つの値(==)は、必ず同じハッシュを生成しなければなりません。どちらかをカスタマイズする場合は、両方の整合性を保ってください。そうしないと、集合や辞書が正しく動作しなくなります。

カスタムhash(into:)

関連するプロパティをハッシャーに渡して、hash(into:)を実装します。

struct User: Hashable {
    let id: Int
    let name: String
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
    static func == (l: User, r: User) -> Bool { l.id == r.id }
}
print(Set([User(id: 1, name: "A"), User(id: 1, name: "B")]).count)  // 1

複数のフィールドを組み合わせる

等価性の判定に関係するすべてのフィールドを渡します。

struct Pair: Hashable {
    let a: Int
    let b: String
    func hash(into hasher: inout Hasher) {
        hasher.combine(a)
        hasher.combine(b)
    }
}
print(Pair(a: 1, b: "x").hashValue == Pair(a: 1, b: "x").hashValue)  // true

識別に使うフィールドだけをハッシュする理由

==で使用するフィールドだけをハッシュしてください。追加の可変フィールドを含めると、「等しい値は同じハッシュになる」という規則に違反する可能性があります。

struct Doc: Hashable {
    let id: Int       // identity
    var title: String // not part of equality
    func hash(into hasher: inout Hasher) { hasher.combine(id) }
    static func == (l: Doc, r: Doc) -> Bool { l.id == r.id }
}
print(Doc(id: 1, title: "v1") == Doc(id: 1, title: "v2"))  // true

Hashableな列挙型

列挙型は自動的にHashableになります。関連値がある場合は、関連値もHashableである必要があります。

enum Direction: Hashable { case north, south, east, west }
let visited: Set<Direction> = [.north, .north, .east]
print(visited.count)  // 2

Setによる重複排除

よくある用途の1つは、Setを経由して重複を削除することです。

let nums = [1, 2, 2, 3, 3, 3]
let unique = Array(Set(nums)).sorted()
print(unique)  // [1, 2, 3]

Hasherは実行ごとにランダム化される

ハッシュ値のシードはプログラムの実行ごとに設定されるため、hashValueをディスクに保存したり、起動をまたいで正確な数値に依存したりしないでください。

struct K: Hashable { let v: Int }
let h1 = K(v: 5).hashValue
// h1 is stable within this run only
print(K(v: 5) == K(v: 5))  // true  -- equality is what to rely on

Dictionaryによるカウント

Hashableなキーは、頻度を数える処理を支えます。非常によく使われるパターンです。

let letters = ["a", "b", "a", "c", "b", "a"]
var counts: [String: Int] = [:]
for l in letters { counts[l, default: 0] += 1 }
print(counts["a"]!)  // 3

確認問題

hash(into:)は、==との関係でどの規則を守る必要がありますか。

まとめ

Hashableについて学びました。

  • HashableはEquatableを拡張し、Setの要素やDictionaryのキーに必要です
  • Hashableのメンバーを持つ構造体と列挙型では自動生成されます
  • カスタムhash(into:)では、==で使用する識別用フィールドだけを組み合わせます
  • 等しい値は同じハッシュにならなければならず、ハッシュは実行ごとにランダム化されます

次はComparableとソートです。

よくある質問

「Hashableとhash(into:)」レッスンは無料ですか?

はい。「Hashableとhash(into:)」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。

「Hashableとhash(into:)」で何を学びますか?

DictionaryのキーやSetの要素として使えるようにします。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Swift Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「Hashableとhash(into:)」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSwift Academyレッスンでコードを書いて実行できますか?

はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Equatableの自動合成
  2. Hashableとhash(into:)
  3. Comparableとソート
  4. カスタム等価性のセマンティクス
← Swift Academyに戻る