142
117

More than 5 years have passed since last update.

ジェネリックプロトコル(Generic Protocol)入門 - associatedtype, typealias, Self -

Last updated at Posted at 2016-08-07

ジェネリックプロトコルについて、わかりやすさを意識して、まとめてみました。
associatedtypeSelfってなんか取っ付きにくいなーと感じている人向けです。

What is Generic Protocol?

ジェネリックプロトコル(Generic Protocol)とは、ジェネリクスを使ったプロトコルです。1
ClassやStructでは<T>などの型パラメーター(Type Parameter)を使う一方、ProtocolではassociatedtypeまたはSelfを宣言します。
associatedtypeSelfも型パラメーター同様、宣言された段階ではまだ抽象的な存在で、Protocolを採用するクラス宣言で初めて具体的な実装がなされます。The Swift Programming Languageでは、型のプレースホルダーと表現されています。

ジェネリックプロトコルの例

話をわかりやすくするために、Animal Protocolというジェネリックプロトコルを作ってみましょう。

Generic
protocol Animal {
    associatedtype FoodType // ※1
    func eat(food: FoodType) // ※2
    func makeFriend(friend: Self) // ※3
}

ここでAnimal Protocolが言っているのは、以下のとおりです。

  • Animal Protocolを使いたければ、クラス宣言のときに、何かしらの型(Type)とFoodTypeを結びつけてね(※1)
  • そうしたら、func eatのfoodは自動的にその型になるよ(※2)
  • func makeFriendで友達になれるのは同じクラスだよ。またSwiftの言語仕様的にサブクラスもOKだよ(※3)

適合するクラスを実装

Animal Protocolに言われたとおり、Catクラスを実装してみます。2

class Cat: Animal {
    typealias FoodType = Mouse
    func eat(food: FoodType) {
        print("yum")
    }

    func makeFriend(friend: Cat) {
        print("Got a new friend!")
    }
}

さて、associatedtypeだった箇所にtypealiasが出てきましたね。typealiasとは、その名の通り、型の別名(エイリアス)のことです。CatクラスではMouseをFoodTypeとして別名指定しました。これでCatのFoodTypeといえばMouseとなり、ネコはfunc eatでネズミを食べられるようになりました:smiley_cat:

まとめ

  • プロトコルをジェネリックに作るにはassociatedtypeもしくはSelfのどちらかを使う
  • associatedtypeで指定された抽象パラメーターを、クラス実装時に具体的な型で指定する。このとき、typealiasを使う。別解↓のようにtypealiasを使わない場合、抽象パラメーターがすでに割り当てられている箇所に具体的な型を入れる。
  • Selfには、適合するクラスあるいはサブクラスが自動的に割り当てられる。

別解

Animalプロトコルに適合したCatの例は以下でも可能です。

1. FoodTypeプレースホルダーに具体的な型を指定する

class Cat: Animal {
    // 引数をMouseにする
    func eat(food: Mouse) {
        print("yum")
    }

    func makeFriend(friend: Cat) {
        print("Got a new friend!")
    }
}

2. ジェネリクスの型パラメーターで型を指定する

// 型パラメーターで制約をつける
class AnyAnimal<FoodType> {
    func eat(food: FoodType) {
        print("yum")
    }

    func makeFriend(friend: AnyAnimal) {
        print("Got a new friend!")
    }
}

//...

let x = AnyAnimal<Mouse>()


  1. The Swift Programming Languageに、"Generic Protocol"という呼び名は出てきませんが、英語圏ではこの呼び名が一般的です。 

  2. このときCatクラスはAnimal Protocolに適合する準拠すると表現します。もしくはAnimal Protocolが採用されるとも言います。前者は英語では"Cat Class conforms to Animal Protocol"、後者は"Animal Protocol is adpoted"です。 

142
117
2

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
  3. You can use dark theme
What you can do with signing up
142
117