ジェネリックス
ある特定のアルゴリズムが、そのデータ型に依存せずにあてはまる場合、型を指定せずに関数なり、コレクションを定義できたら便利です。
例えばリストがあったとして、Int のリストも String のリストも、同様の使い方をしたい場合、型によらない実装をしておき、 必要に応じて型を指定できたら便利です。
例えば、Dictionary のコレクションで、キーも値も String という場合は、次のように < と > にて String を指定します。
var d = Dictionary<String, String>()
d["a"] = "Hello"
d["b"] = "World"
for ( key , val ) in d {
print( "\(key) - \(val)" )
}
a - Hello b - World
このように型によらないアルゴリズムを汎用の型としてテンプレートを実装しておき、後で必要に応じて型を指定する実装をジェネリックス (Generics) といいます。
ジェネリックスを使うと、関数の定義を次のようにかけます。< と > に型を表す文字を書きます。
func myfunc<T>( a : inout T , b : inout T ){
let temp = a
a = b
b = temp
}
var i = 1
var j = 3
print( "i = \(i) - j = \(j)" )
myfunc( a: &i , b: &j )
print( "i = \(i) - j = \(j)" )
var s = "Hanako"
var t = "Ichiro"
print( "s = \(s) - t = \(t)" )
myfunc( a: &s , b: &t )
print( "s = \(s) - t = \(t)" )
i = 1 - j = 3 i = 3 - j = 1 s = Hanako - t = Ichiro s = Ichiro - t = Hanako
実行時に、Int 型及び String 型どちらでも動作が確認できますね。
プロトコル定義でのジェネリックス
ジェネリックスの基本的な考え方には変わりありませんが、プロトコル定義でのジェネリックス利用方法を紹介します。
プロトコルでは associatedtype で型を示す文字を指定します。ここでは T という文字を使っています。
Swift 2.2 より前のバージョンでは typealias というキーワードが使われていました。
protocol Foo {
associatedtype T
func myfunc( a : T )
}
class Bar : Foo {
func myfunc( a : Int ) {
print( "\(a)" )
}
}
var b = Bar()
b.myfunc( a: 5 )
5
このプロトコルを実装する場合は、タイプエイリアスは実際の型を指定します。