0
1

More than 3 years have passed since last update.

[Swift]推定されるジェネリック型の制約

Posted at

※この記事はSwift by Sundellの内容を日本語に翻訳したものです。

ジェネリック型制約を使用して、特定のAPIが使用される具象型に一連の要件を課すことができます。これにより、ジェネリックコード内でそれらの型について特定の仮定を行うことができます。

たとえば、私たちが取り組んでいるアプリがNetworkRequestプロトコルを使用して、さまざまなリクエストを、それぞれResponseが期待する種類を宣言するさまざまなタイプとして定義できるようにしているとします。

protocol NetworkRequest {
    associatedtype Response: Codable

    func makeURLRequest() -> URLRequest
}

このようなリクエストを実行するためのAPIを定義すると、次のような結果になる可能性があります。ジェネリック型制約を使用して、そのT型が実際に上記のプロトコルに準拠していることを確認する関数です。

func perform<T: NetworkRequest>(
    _ request: T,
    then handler: @escaping (Result<T.Response, Error>) -> Void
) {
    ...
}

ここで、NetworkRequestQueueクラスを使用してリクエストをキューに入れるためのサポートも追加したいとします。これも、NetworkRequestプロトコルに制約されたジェネリック型を使用します。

class NetworkRequestQueue<Request: NetworkRequest> {
    ...
}

上記のクラスのインスタンスをperform関数に挿入するためのパラメーターを追加する場合、最初は次のようにパラメーターのリストに追加するだけです。

func perform<T: NetworkRequest>(
    _ request: T,
    on queue: NetworkRequestQueue<T>,
    then handler: @escaping (Result<T.Response, Error>) -> Void
) {
    ...
}

ただし、NetworkRequestQueueクラスでは、NetworkRequestプロトコルに準拠するために汎用のRequestタイプがすでに必要であり、コンパイラは、そのクラスを特殊化するために使用されるタイプがリクエストパラメータに使用されるタイプと同じであることを認識しているため、実際には省略できます。次のように、perform関数からの型制約を完全に実行します。

func perform<T>(
    _ request: T,
    on queue: NetworkRequestQueue<T>,
    then handler: @escaping (Result<T.Response, Error>) -> Void
) {
    ...
}

上記は細かいことのように思えるかもしれませんが、おそらくそれは物事の壮大なスキームにあります—しかし、ジェネリックコードは非常に冗長になる傾向があるため、特に型制約を使用する場合、そのような冗長性を減らすためにできることは間違いなく良いことです。

追加のボーナスとして、上記のhandlerパラメーターのクロージャー型も少し単純にしましょう。最初に、NetworkRequestプロトコルの拡張機能内で型エイリアスに変換します。

extension NetworkRequest {
    typealias ResponseHandler = (Result<Response, Error>) -> Void
}

上記を実行すると、perform関数のシグネチャをさらに読みやすくすることができます—次のようになります。

func perform<T>(
    _ request: T,
    on queue: NetworkRequestQueue<T>,
    then handler: @escaping T.ResponseHandler
) {
    ...
}

Swiftの構文は、ジェネリック型と関数の定義に関しては最初はかなり冗長に見えるかもしれませんが、読みやすさを犠牲にすることなく、そのような定義をはるかにコンパクトにするために使用できる特定のトリックとテクニックがよくあります。

元の記事

Inferred generic type constraints Swift by Sundell

0
1
0

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
0
1