Article

Adopting Common Protocols 一般的なプロトコルを採用する

Make your custom types easier to use by ensuring that they conform to Swift protocols. あなたのカスタム型を、それらがSwiftプロトコルに準拠するのを確実にすることで、より簡単に使えるようにします。

Overview 概要

When using custom types to model data in your programs, you may frequently need to check whether two values are the same or different, or whether a particular value is included in a list of values. This capability, as well as the ability to store values in a set or use them as keys in a dictionary, are governed by two related standard library protocols, Equatable and Hashable. あつらえの型を使ってあなたのプログラムにおいてデータをモデル化する場合、あなたは2つの値が同じか異なるか、または特定の値が値のリストに含まれるかどうかを調べる必要がしばしばあるかもしれません。これができる力、それだけでなくいくらかの値を集合の中に格納するまたはそれらを辞書においてキーとして使う能力は、2つの関連する標準ライブラリプロトコル、EquatableHashableによって管理されます。

  • You can compare instances of an equatable type by using the equal-to (==) and not-equal-to (!=) operators. あなたは、equatable型のインスタンスを比較することが、同等(==)および不等(!=)演算子によって行えます。

  • An instance of a hashable type can reduce its value mathematically to a single integer, which is used internally by sets and dictionaries to make lookups consistently fast. hashable型のインスタンスは、それの値を単一の整数へと数学的に還元できます、それは検索を常に高速なものにするために集合と辞書によって内部的に使われます。

Many standard library types are both equatable and hashable, including strings, integers, floating-point values, Boolean values, and collections of equatable and hashable types. The == comparison and the contains(_:) method call in the following example depend on strings and integers being equatable: 多くの標準ライブラリ型は、文字列、整数、浮動点小数値、ブール値、そしてequatableとhashable型のコレクション型を含めて、equatableとhashableの両方です。==比較とcontains(_:)メソッド呼び出しは以下の例において、文字列と整数がequatableであることに依存します:


if username == "Arturo" {
    print("Hi, Arturo!")
}


let favoriteNumbers = [4, 7, 8, 9]
if favoriteNumbers.contains(todaysDate.day) {
    print("It's a good day today!")
}

Conforming to the Equatable and Hashable protocols is straightforward and makes it easier to use your own types in Swift. It's a good idea for all your custom model types to conform. EquatableHashableプロトコルに準拠することは、あなた独自の型をSwiftで使うのをわかりやすいそしてより容易なものにします。あなたのあつらえのモデル型すべてにとって準拠することは良い考えです。

Conform Automatically to Equatable and Hashable 自動的にequatableとhashableに準拠する

You can make many custom types equatable and hashable by simply declaring these protocol conformances in the same file as the type's original declaration. Add Equatable and Hashable to the list of adopted protocols when declaring the type, and the compiler automatically fills in the requirements for the two protocols: あなたは、多くのあつらえの型をequatableおよびhashableにすることが、単にそれらプロトコル準拠をその型の原型の宣言と同じファイルにおいて宣言することによって行えます。EquatableおよびHashableを型を宣言する時に採用するプロトコルのリストに加えてください、するとコンパイラは自動的に2つのプロトコルに対する要件を満たします:


/// A position in an x-y coordinate system.
struct Position: Equatable, Hashable {
    var x: Int
    var y: Int
    
    init(_ x: Int, _ y: Int) {
        self.x = x
        self.y = y
    }
}

With Equatable conformance, you can use the equal-to operator (==) or the not-equal-to operator (!=) with any two instances of the Position type. Equatable準拠で、あなたは同等演算子(==)または不等演算子(!=)をPosition型の任意の2つのインスタンスで使用できます。


let availablePositions = [Position(0, 0), Position(0, 1), Position(1, 0)]
let gemPosition = Position(1, 0)


for position in availablePositions {
    if gemPosition == position {
        print("Gem found at (\(position.x), \(position.y))!")
    } else {
        print("No gem at (\(position.x), \(position.y))")
    }
}
// No gem at (0, 0)
// No gem at (0, 1)
// Gem found at (1, 0)!

Hashable conformance means that you can store positions in a set and quickly check whether you've visited a position before, as shown in the following example: Hashable準拠は、あなたが集合の中の位置を格納して前にあなたが訪れた位置かどうかを素早く確認できることを意味します、以下の例で示すように:


var visitedPositions: Set = [Position(0, 0), Position(1, 0)]
let currentPosition = Position(1, 3)


if visitedPositions.contains(currentPosition) {
    print("Already visited (\(currentPosition.x), \(currentPosition.y))")
} else {
    print("First time at (\(currentPosition.x), \(currentPosition.y))")
    visitedPositions.insert(currentPosition)
}
// First time at (1, 3)

In addition to simplifying your code, this automatic conformance reduces errors, because any new properties you add to your custom types are automatically included when hashing and testing for equality. A type is eligible for automatic conformance to Equatable and Hashable when it's a structure or an enumeration that meets these criteria: あなたのコードを単純にすることに加えて、この自動式の準拠はエラーを減らします、なぜならあなたのあつらえの型にあなたが加える何らかの新しいプロパティは、ハッシュ化および同等性テストをする場合に自動的に含まれるからです。ある型がEquatableおよびHashableへの自動式準拠に適格であるのは、それが構造体または列挙であり、これらの基準に合う場合です:

  • For a structure, all its stored properties must conform to Equatable and Hashable. 構造体に対して、全てのそれの格納プロパティは、EquatableおよびHashableに準拠しなければなりません。

  • For an enumeration, all its associated values must conform to Equatable and Hashable. (Enumerations without associated values have Equatable and Hashable conformance even without declaring adoption.) 列挙に対して、全てのそれの関連値は、EquatableおよびHashableに準拠しなければなりません。(関連値なしの列挙は、EquatableおよびHashable準拠を持ちます、たとえ採用を宣言することなしでも。)

Conform Manually to Equatable and Hashable 手動でequatableとhashableに準拠する

You need to manually implement Equatable and Hashable conformance for a type in these cases: あなたは、手動でEquatableHashable準拠をある型に対して実装する必要がこれらの場合には必要です:

  • The type doesn't meet the criteria listed in the previous section. その型が以前の節においてリストされる基準に合わない。

  • You want to customize the type's conformance. あなたがその型の持つ準拠をカスタマイズしたい。

  • You want to extend a type declared in another file or module to conform. あなたが別のファイルまたはモジュールにおいて宣言される型を拡張することで準拠したい。


class Player {
    var name: String
    var position: Position
    
    init(name: String, position: Position) {
        self.name = name
        self.position = position
    }
}

The Player type is a class, so it doesn't qualify for automatic synthesis of the Equatable or Hashable requirements. To make this class conform to the Equatable protocol, declare conformance in an extension and implement the static == operator method. Compare each significant property for equality in your == method's implementation: Player型はクラスです、なのでそれはEquatableまたはHashable要件の自動的な合成の基準を満たしません。このクラスをEquatableプロトコルに準拠させるには、準拠をある拡張において宣言して、静的==演算子メソッドを実装してください。重要なプロパティそれぞれを同等性についてあなたの==メソッドの実装において比較してください:


extension Player: Equatable {
    static func ==(lhs: Player, rhs: Player) -> Bool {
        return lhs.name == rhs.name && lhs.position == rhs.position
    }
}

To make Player conform to the Hashable protocol, declare conformance in another extension and implement the hash(into:) method. In the hash(into:) method, call the combine(_:) method on the provided hasher with each significant property: PlayerHashableプロトコルに準拠させるには、準拠を別の拡張において宣言して、hash(into:)メソッドを実装してください。hash(into:)メソッドにおいて、combine(_:)メソッドをその提供されたhasher上で各重要プロパティとともに呼び出してください:


extension Player: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(position)
    }
}

Use All Significant Properties for Equatable and Hashable すべての重要プロパティをequatableとhashableに対して使う

When implementing the == method and the hash(into:) method, use all the properties that affect whether two instances of your custom type are considered equal. In the implementations above, the Player type uses name and position in both methods. ==メソッドとhash(into:)メソッドを実装する場合、あなたのカスタム型の2つのインスタンスが等しいと考えられるどうかに影響するすべてのプロパティを使ってください。上の実装において、Player型はnamepositionを両方のメソッドにおいて使います。

If your type contains properties that don't affect whether two instances are considered equal, exclude those properties from comparison in the == method and from hashing in hash(into:). For example, a type might cache an expensive computed value so that it only needs to calculate it once. If you compare two instances of that type, whether or not the computed value has been cached shouldn't affect their equality, so the cached value should be excluded from comparison and hashing. 2つのインスタンスが等しいと考えられるかどうかに影響しないプロパティをあなたの型が含むならば、それらプロパティを==メソッドでの比較から、そしてhash(into:)でのハッシュ化から除外してください。例えば、ある型は高くつく計算値をキャッシュするかもしれません、それを計算する必要がただ一度だけであるように。あなたがその型の2つのインスタンスを比較するならば、計算値がキャッシュされるかどうかが、それらの同等性に影響すべきではありません、なのでキャッシュされた値は比較およびハッシュ化から排除されるべきです。

Customize NSObject Subclass Behavior NSObjectサブクラス挙動をカスタマイズする

NSObject subclasses inherit conformance to the Equatable and Hashable protocols, with equality based on instance identity. If you need to customize this behavior, override the isEqual(_:) method and hash property instead of the == operator method and hashValue property. NSObjectサブクラスは、EquatableHashableプロトコルへの準拠を継承します、インスタンス同一性に基づく同等性を使います。あなたがこの挙動をカスタマイズする必要があるならば、isEqual(_:)メソッドとhashプロトコルをオーバーライドしてください、==演算子メソッドとhashValueプロパティではなく。


extension MyNSObjectSubclass {
    override func isEqual(_ object: Any?) -> Bool {
        guard let other = object as? MyNSObjectSubclass
            else { return false }
        return self.firstProperty == other.firstProperty 
            && self.secondProperty == other.secondProperty
    }


    override var hash: Int {
        var hasher = Hasher()
        hasher.combine(firstProperty)
        hasher.combine(secondProperty)
        return hasher.finalize()
    }
}

As noted in the previous section, two instances that are considered equal must have the same hash value. If you override one of these declarations, you must also override the other to maintain that guarantee. 前の節で注記されるように、等しいとみなされる2つのインスタンスは、同じハッシュ値を持たなければなりません。あなたがそれら宣言の一方をオーバーライドするならば、あなたはまた他方もオーバーライドしてその保証を維持してください。

See Also 参照

Data Modeling データモデリング