ジェネリック型 / where句
| 対応: | Swift 1.0(2014) |
|---|
Swiftのジェネリック型は、型パラメータを持つ struct・class・enum です。以下は発展的な使い方です。ジェネリクスの基本を理解した上で読み進めてください。
『where』句を使うことで、型パラメータへの複雑な制約を表現できます。
構文
// ジェネリック struct
struct 型名<T> {
var items: [T]
mutating func push(_ item: T) { items.append(item) }
mutating func pop() -> T? { return items.popLast() }
}
// ジェネリック関数に where 句
func 関数名<T, U>(_ t: T, _ u: U) where T: Equatable, U: Hashable {
// 処理
}
// extension に where 句(条件付き extension)
extension Array where Element: Numeric {
var sum: Element { return reduce(0, +) }
}
構文一覧
| 構文 | 概要 |
|---|---|
| struct 名前<T> { } | 型パラメータを持つジェネリック構造体を定義します。 |
| where T: プロトコル | 型パラメータに対してプロトコル準拠の制約を付けます。 |
| where T == U | 2つの型パラメータが同じ型であることを要求します。 |
| associatedtype | プロトコル内で使う型プレースホルダーを定義します。 |
| extension 型<T> where T: 制約 | 特定の条件を満たす場合のみ有効な extension を定義します。 |
サンプルコード
ジェネリック型と『where』句を使った型制約の書き方を確認するサンプルコードです。
sample_generic_type_where.swift
// ジェネリックなスタック
struct Stack<T> {
private var items: [T] = []
mutating func push(_ item: T) {
items.append(item)
}
mutating func pop() -> T? {
return items.popLast()
}
var top: T? { return items.last }
var isEmpty: Bool { return items.isEmpty }
var count: Int { return items.count }
}
var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
intStack.push(3)
print("スタック top: \(intStack.top!)")
print("pop: \(intStack.pop()!)")
// 関連型(associatedtype)を持つプロトコル
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
// where 句で関連型に制約
func compareContainers<C1, C2>(_ c1: C1, _ c2: C2) -> Bool
where C1: Container, C2: Container, C1.Item == C2.Item, C1.Item: Equatable {
guard c1.count == c2.count else { return false }
for i in 0..<c1.count {
if c1[i] != c2[i] { return false }
}
return true
}
// 条件付き extension
extension Stack: Equatable where T: Equatable {
static func == (lhs: Stack, rhs: Stack) -> Bool {
return lhs.items == rhs.items
}
}
let stack1 = Stack<Int>()
let stack2 = Stack<Int>()
print("空スタック比較: \(stack1 == stack2)")
swift generic_type_where.swift スタック top: 3 pop: 3 空スタック比較: true
概要
ジェネリック型を使うことで、異なる型で動作する汎用的なデータ構造を定義できます。Swift の標準ライブラリの Array・Dictionary・Optional もジェネリック型として実装されています。
『where』句は『:』で書ける単純な制約と違い、複数の制約や型同士の関係(T.Element == U など)を表現できます。associatedtype を持つプロトコルは通常の型として使えず、ジェネリック制約(where句)の中でのみ使えます。Swift 5.7 以降は any プロトコル名 で使えるようになりました。
some / any の使い方についてはsome / any / opaque typeを参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。