Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

ジェネリックプロトコルについて、わかりやすさを意識して、まとめてみました。
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"です。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした