1. ホーム
  2. oop

[解決済み] なぜプロトコルの関連型はSwiftの汎用型構文を使用しないのですか?

2023-04-22 05:52:41

質問

プロトコルの関連型に使用される構文と、汎用型の違いについて混乱しています。

Swiftでは、例えば、次のようなものを使って一般的な型を定義することができます。

struct Stack<T> {
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
}

のようなものを使って、関連する型を持つプロトコルを定義することができます。

protocol Container {
    associatedtype T
    mutating func append(item: T)
    var count: Int { get }
    subscript(i: Int) -> T { get }
}

なぜ後者だけではないのか。

protocol Container<T> {
    mutating func append(item: T)
    var count: Int { get }
    subscript(i: Int) -> T { get }
}

この言語が後者の構文を採用しないのは、何か深い(あるいは単に明白で私に理解できない)理由があるのでしょうか?

どのように解決するのですか?

これはdevlistで何度か取り上げられています。基本的な答えは、関連付けられた型は型パラメータよりも柔軟であるということです。ここでは型パラメーターが 1 つという特殊なケースですが、複数の型パラメーターを持つことも十分可能です。例えば、Collectionsには、Elementタイプだけでなく、IndexタイプやGeneratorタイプもあります。これらをすべて型パラメタ化で特化すると、次のような話になります。 Array<String, Int, Generator<String>> などと言わなければならない。(これによってInt以外のものを添え字にした配列を作ることができるようになり、それは機能として考えられるが、複雑さも増す)

すべてを省略することは可能ですが(Javaはそうしています)、その場合、型を制約することができる方法が少なくなります。実際、Java は型を制約する方法がかなり制限されています。Javaでは、コレクションに任意のインデックス型を設定することはできません。Scalaは、Swiftと同じように、Javaの型システムを連想型によって拡張しています。関連付けられた型は、Scala において信じられないほど強力なものでした。彼らはまた、混乱と髪の毛の涙の定期的なソースです。

この余分なパワーがそれに値するかどうかは、全く別の問題であり、時間だけがそれを教えてくれるでしょう。しかし、関連付けられた型は間違いなく単純な型のパラメタリゼーションよりも強力です。