はじめに
Swift5.7からSelf
またはassociated type
を持ったprotocol
が型として定義できるようになりましたね!
これによって今まで型消去のテクニックを使って実装していた部分がよりシンプルに書けるようになりました。
そもそも型消去って何よ
associated type
を持ったprotocol
が型として定義できないとは
Swift5.7未満ではassociated type
を持ったprotocol
を型として定義できませんでした。
どう言うことか実際に処理として表現してみます。
protocol Repository {
associatedtype Entity
func fetch() -> Entity
}
struct SampleEntity {
let text: String
}
class SampleRepository: Repository {
typealias Entity = SampleEntity
func fetch() -> Entity {
return SampleEntity(text: "")
}
}
上記ではRepository
がassociated type
を持ったprotocol
として定義されています。
では、実際にRepository
を型として定義しようとするとどうなるか見てみましょう。
// Repositoryはassociatedtypeを持っていて型として定義できないためエラーが出る
var repository: Repository = SampleRepository()
上記のようにRepository
を変数の型に指定しようとするとエラーが出てしまいます。
このような場合、型消去のテクニックを使うことでエラーを回避しつつ、上記でやりたかったことを実現することが出来ます。
型消去テクニックを使って解決してみる
では、上記のコードを型消去のテクニックを使って実装してみましょう。
struct AnyRepository<Entity>: Repository {
typealias Entity = Entity
private let _fetch: (() -> Entity)
init<T: Repository>(_ repository: T) where T.Entity == Entity {
_fetch = repository.fetch
}
func fetch() -> Entity {
return _fetch()
}
}
var repository: AnyRepository<SampleEntity> = AnyRepository(SampleRepository())
repository.fetch()
Repository protocol
を直接型に定義しないで、AnyRepository
というものを噛ませているのがわかると思います。
AnyRepository
はイニシャライザでRepository
に準拠したクラスを受け取り、そのクラスが持つRepository
に準拠している関数をAnyRepository
で変数に保持しておきます。
そして、AnyRepository
のfetch
関数等が呼ばれた際に保持していおいた関数を呼び出すことで、イニシャライザで代入したクラスの処理を実施出来ます。
AnyRepository
はprotocol
ではないため、型としても問題なく定義できます。
Repository
をAnyRepository
に変換してしまうことで、元のRepository
を型として定義することなく使うことが出来ます。
型消去を使わない方法
ここまで読んでいたいだら薄々勘づいているかと思うのですが、型消去をするためにAnyRepository
等といったボイラープレートコードを毎回用意するの面倒じゃないですか?
面倒だと思った方でかつSwift5.7以上を以上を使用している方がいらっしゃいましたらご安心ください、Swift5.7以降では型消去のテクニックを使わずに実装できます。
ようやくここから本題です。
どうやって型消去を使わずに実装するの?
至って簡単です、下記のように定義しましょう。
var repository: any Repository = SampleRepository()
これで終わりですか?
はい、終わりです。
associated type
を持ったprotocol
を型として定義する際に、型の前にany
を付けてあげるだけです。
AnyRepository
等を作成する必要もありません。
本題より型消去の話の方が長い。
終わりに
型消去を現時点で使っている箇所は上記でリファクタリングすることでボイラープレートを削減でき、見通しも良くなるので検討の余地ありかなと思います。