207
200

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-06-08

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

参照: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
207
200
0

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
207
200

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?