ジェネリックス

ある特定のアルゴリズムが、そのデータ型に依存せずにあてはまる場合、型を指定せずに関数なり、コレクションを定義できたら便利です。

例えばリストがあったとして、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

このプロトコルを実装する場合は、タイプエイリアスは実際の型を指定します。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Swift による iOS 開発入門