search
LoginSignup
49

More than 3 years have passed since last update.

posted at

updated at

swiftでprotocolでのgenericsに型制約を付ける

swiftでprotocolを汎化しようとした場合、以下のように定義が出来ます


protocol Entity {
    associatedtype IdentityType
    var identity:IdentityType { get }
}

Entityであるのならば、identityという何らかの型の変数を持っていると定義しています。

ここでさらにIdentityTypeに型制約を付たい場合、protocolでは以下のように定義します。


protocol Entity {
    associatedtype IdentityType: Equatable
    var identity:IdentityType { get }
}

Genericsに型制約を付けるのと同じ記述をtypealiasにしてあげるだけですね。

複数の制約をつける事も出来ます


protocol Entity {
    associatedtype IdentityType: Equatable, Comparable
    var identity:IdentityType { get }
}

本題からは少し外れますが、このような制約をつけていくとprotocolの性質を明確に出来る他に、Genericsの関数を作ってコードの量を減らせるというメリットも出てきます

例えば、EntityへEquatableの制約を付け足した場合


protocol Entity: Equatable {
    associatedtype IdentityType: Equatable, Comparable
    var identity:IdentityType { get }
}

func == <T:Entity> (lhs : T, rhs : T) -> Bool {
    return lhs.identity == rhs.identity
}

上記のようなEntityを受け取る関数を一つ定義してあげれば良いようになります。
(Identityを比較すれば良いという条件ではあるけれど、)

実際にクラスを実装する場合はこのようになります
例えばIntをidentityにすると、IntEquatableComparableを実装しているのでコンパイルが通ります


// OK
class MyEntity : Entity {
    // 補足: getがあれば良いのでletでもvarでも良い
    let identity: Int = 0
}

ComparableEquatableを実装していない型をIdentityにするとエラーになります


// Fail Type MyEntity does not conform to protocol `Entity`
class MyEntity : Entity {
    let identity: NantokaType = NantokaType()
}

Genericsはうまい事使えば型安全を保って無駄のないコードが書けそうなので、もっと活用していきたいですね。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
49