LoginSignup
2
2

More than 3 years have passed since last update.

【Swift】ジェネリクスについて改めて調べてみた

Last updated at Posted at 2020-07-01

業務でSwiftに携わり始めた頃、クラスやメソッド名の隣に書かれている<>の意味が分からずに困っていました。しかもなんて調べたら<>←この正体に出会えるのかも分からない。
随分後になってこれがジェネリクスという記法だということを知りました。

そんなジェネリクスについてまとめたいと思います。

ジェネリクスとは

汎用的な実装をするための技術です。
通常関数の引数はIntStringなど、型を決めて宣言します。もちろん宣言した型以外は変数に入れることはできません。しかしジェネリクスを使うと、同じ関数の引数に違う型を渡すことができるのです。

Swiftにはジェネリック関数ジェネリック型があります。

ジェネリック関数

型引数(<>で囲まれたやつ)をもつ関数のことです。

func get<T: Equatable>(_ x: T) -> T {
    // 返り値は引数と同じ型になる
    return x
}

get(1) // 1: Int
sum("a") // a: String

// 複数の引数を違う方で受け取りたい場合、型引数を2つ定義する
func get<T, U>(_ x: T, y: U) { }

get(1, "String")

<T: Equatable>Equatableプロトコルに準拠した型を意味します。これを型制約と言います。
sum(1, 2)のように、ジェネリック関数またはジェネリック型に具体的な型引数を与えて型を確定することを特殊化と言います。

ジェネリック型

型引数をもつクラスや構造体・列挙型のことです。

// クラス
class SampleClass<T> {}
// 構造体
struct SampleStruct<T> {}
// 列挙型
enum SampleEnum<T> {}

型の安全性は保たれるのか?

ジェネリクスは汎用性と型の安全性を兼ね備えています。対象にジェネリクスと同様に汎用的な実装を可能にするAnyは型の安全性を備えていません。Anyは暗黙的に型推論される為、具体的な型として扱いたい時はダウンキャストが必要になります。

func get<T: Equatable>(_ x: T) -> T {
    return x
}

get(1) // 1: Int

// ------- 先ほどのこれをAnyを使って実現させたい場合---------

func get(_ x: Any) -> Any { 
   if let intX = x as? Int { return intX }
}

let anyGet = get(1) // Any型
if let intGet = anyGet as? Int { // get(1)のInt型が取れる }

Anyは具体的な引数を渡してもAny型のままなので、こんな感じで都度ダウンキャストする必要があります。

ジェネリクスとAnyを使い分けて活用すればかなり汎用的な実装が可能になりそうですね。

*2020/7/1 コメント頂きもう少し分かりやすく修正しました。

2
2
3

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
2
2