Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
111
Help us understand the problem. What is going on with this article?
@mshrwtnb

ジェネリックプロトコル(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"です。 

111
Help us understand the problem. What is going on with this article?
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
globis
グロービスは 1992 年の創業以来、社会人を対象とした MBA、人材育成の領域で Ed-Tech サービスを提供し、現在は日本 No.1 の実績があります。これらの資産と、さらに IT や AI を活用することで、アジア No.1 を目指しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
111
Help us understand the problem. What is going on with this article?