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

Swiftのジェネリックスについてのメモ

More than 5 years have passed since last update.

自分がジェネリックスという単語自体が初めて聞く言葉であり、
よく理解できてないのでまとめてみた

参照:The Swift Programming Language (iBooks)

Genericsとは

クラスや関数を使う側が扱う型を指定できるようにする仕組み
これにより、抽象的なコードを記述することを可能にする

関数でのGenerics

関数内で使用する任意の型を定義できる

1. 型制約なし

型の制約がないので、どんな型の場合でも使用することができる
任意の型は名前は自由(ただし、UpperCamelCaseであること)

func 関数名 <任意の型> () {
    // 任意の型を使用した処理
}

例) ItemTypeという任意の型を引数と戻り値と内部で使用している

func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
    var result = ItemType[]()
    for i in 0..times {
        result += item
    }
    return result
}

// ItemTypeがStirngの場合
repeat("knock", 4)    // ["knock", "knock", "knock", "knock"]

// ItemTyoeがIntの場合
repeat(10, 4)         // [10, 10, 10, 10]


抜粋: Apple Inc. The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l

2. 型制約あり

func 関数名 <任意の型: クラス名 または プロトコル名> () {
    // 任意の型を使用した処理
}

例) 使用できる型(T)がEquatableプロトコルに準拠した型だけに制限される

func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
    for (index, value) in enumerate(array) {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

抜粋: Apple Inc. The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l

構造体でのGenerics

クラス、構造体、列挙で使用する任意の型を定義することができる

例) 任意の型の値の要素を持つスタック

struct Stack<T> {
    var items = T[]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var stack = Stack<String>()  // <String>と記述することで"String型"で指定する
stack.push("A")
stack.push("B")
stack.items    // ["A", "B"]

stack.push(100) // String以外受け付けないのでエラー

抜粋: Apple Inc. The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l

プロトコルでのGenerics

プロトコル内で使用する任意の型を定義できる
このとき、typealiasに任意の型名を指定しておく

例) ItemTypeという任意の型を使用しているプロトコル

プロトコルの宣言

protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get } // { get }はgetter処理の実装を必須とする
    subscript(i: Int) -> ItemType { get }
}

抜粋: Apple Inc. The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l

Containerプロトコルに準拠した構造体
ここで任意の型をIntとして固定

// 任意の型をIntとして実装
struct IntStack: Container {
    // original IntStack implementation
    var items = Int[]()
    mutating func push(item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
    // conformance to the Container protocol
    typealias ItemType = Int
    mutating func append(item: Int) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Int {
        return items[i]
    }
}

抜粋:: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l

こちらはGenericsの構造体にContainerプロトコルを準拠させたパターン
こちらは、typealiasにセットはしていないが、
任意の型(T型)をitemとappendとsubscriptで使用していることから、
ItemTypeとしてT型を使用していることが推測できる

struct Stack<T>: Container {
    // original Stack<T> implementation
    var items = T[]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
    // conformance to the Container protocol
    mutating func append(item: T) {
        self.push(item)
    }
    var count: Int {
    return items.count
    }
    subscript(i: Int) -> T {
        return items[i]
    }
}

抜粋:: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l

whereを使った型指定

型指定にプロトコルを指定するときに、
さらに、そのプロトコルの内容で細かく制限をかけることができる

例)

Containerプロトコルを実装したC1とC2という型で指定
それ以外に以下の指定を行う

  • C1のItemTypeにEquatableプロトコルの型が入っていること
  • C1のItemTypeとC2のItemTypeが同じ型であること
func allItemsMatch
     <C1: Container, C2: Container
      where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
     (someContainer: C1, anotherContainer: C2) -> Bool {

        // check that both containers contain the same number of items
        if someContainer.count != anotherContainer.count {
            return false
        }

        // check each pair of items to see if they are equivalent
        for i in 0..someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }

        // all items match, so return true
        return true

}

抜粋: Apple Inc. The Swift Programming Language”。 iBooks. https://itun.es/jp/jEUH0.l
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
ユーザーは見つかりませんでした