1. ホーム
  2. swift

[解決済み] プロトコルは自分自身に適合しない?

2022-06-02 05:05:08

質問

なぜこのSwiftコードはコンパイルできないのでしょうか?

protocol P { }
struct S: P { }

let arr:[P] = [ S() ]

extension Array where Element : P {
    func test<T>() -> [T] {
        return []
    }
}

let result : [S] = arr.test()

コンパイラは次のように言っています: "タイプ P はプロトコルに適合していません。 P "(または、Swiftの後のバージョンでは、"プロトコル 'P' に準拠した具象型として 'P' を使用することはサポートされていません.")。

なぜダメなのでしょうか?これは、何となく、言語の穴のように感じます。私は、この問題は、配列 arr を配列として をプロトコル型の というのがありますが、これは不合理なことなのでしょうか?プロトコルは、構造体に型階層のようなものを提供するために存在するのでは?

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

編集:Swiftでの作業でさらに18ヶ月、別のメジャーリリース(新しい診断を提供する)、そして@AyBayBayからのコメントで、この答えを書き直したくなりました。新しい診断は

"プロトコル 'P' に準拠した具象型として 'P' を使用することはサポートされていません."

これで実際、この件がかなり明確になりましたね。このエクステンションは

extension Array where Element : P {

が適用されないのは Element == P から P の具体的な適合性とはみなされないからです。 P . (以下の "put it in a box" ソリューションはまだ最も一般的なソリューションです)。


古い回答です。

それはまた別のメタタイプのケースです。Swift は本当に は、ほとんどの非自明な事柄のために具象型に到達することを望んでいます。 [P] は具象型ではありません (既知の大きさのメモリブロックを P ). (実際にはそうではないと思います。サイズ P なぜなら というのは、それはインダイレクトで行われるからです。 .) これが "shouldn't" のケースであるという根拠はないと思うのですが。これは、彼らの "doesn't work yet" ケースのひとつに非常によく似ているようです。(残念ながら、これらのケースの違いをAppleに確認させることはほとんど不可能です)。という事実は Array<P> が変数型になりうるということです (ここで Array はできない) は、彼らがすでにこの方向でいくつかの仕事をしたことを示しますが、Swift のメタタイプは鋭いエッジと未実装のケースがたくさんあります。私はあなたがそれよりも良い"なぜ"答えを得るつもりはないと思います。 "コンパイラがそれを許可していないからです。

解決策は、ほとんどの場合、物事を箱に入れることです。タイプイレイザーを作るのです。

protocol P { }
struct S: P { }

struct AnyPArray {
    var array: [P]
    init(_ array:[P]) { self.array = array }
}

extension AnyPArray {
    func test<T>() -> [T] {
        return []
    }
}

let arr = AnyPArray([S()])
let result: [S] = arr.test()

Swift がこれを直接できるようにするとき (私はいずれそうなることを期待しています)、それはおそらく、あなたのためにこのボックスを自動的に作成することだけになるでしょう。再帰的な列挙はまさにこの歴史を持っていました。あなたはそれらをボックス化しなければならず、それは信じられないほど迷惑で制限的でした。そして最終的にコンパイラは indirect を追加して、同じことをより自動的に行うようにしました。