协议不符合自身? [英] Protocol doesn't conform to itself?

查看:49
本文介绍了协议不符合自身?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么这个 Swift 代码不能编译?

Why doesn't this Swift code compile?

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".").

The compiler says: "Type P does not conform to protocol P" (or, in later versions of Swift, "Using 'P' as a concrete type conforming to protocol 'P' is not supported.").

为什么不呢?不知何故,这感觉像是语言中的一个漏洞.我意识到问题源于将数组 arr 声明为一个协议类型的数组 ,但这是不合理的做法吗?我认为协议确实可以帮助提供具有类型层次结构之类的结构?

Why not? This feels like a hole in the language, somehow. I realize that the problem stems from declaring the array arr as an array of a protocol type, but is that an unreasonable thing to do? I thought protocols were there exactly to help supply structs with something like a type hierarchy?

推荐答案

与 Swift 一起工作了 18 个月,这是另一个主要版本(提供新的诊断),@AyBayBay 的评论让我想重写这个答案.新的诊断是:

Eighteen more months of working w/ Swift, another major release (that provides a new diagnostic), and a comment from @AyBayBay makes me want to rewrite this answer. The new diagnostic is:

不支持将‘P’用作符合协议‘P’的具体类型."

"Using 'P' as a concrete type conforming to protocol 'P' is not supported."

这实际上使整个事情变得更加清晰.这个扩展:

That actually makes this whole thing a lot clearer. This extension:

extension Array where Element : P {

Element == P 时不适用,因为 P 不被认为是 P 的具体一致性.(下面的put it in a box"方案仍然是最通用的方案.)

doesn't apply when Element == P since P is not considered a concrete conformance of P. (The "put it in a box" solution below is still the most general solution.)

旧答案:

这是元类型的另一种情况.Swift 真的希望你为大多数重要的事情找到一个具体的类型.[P] 不是一个具体的类型(你不能为 P 分配一个已知大小的内存块).(我不认为确实如此;您绝对可以创建 P 大小的东西,因为 它是通过间接完成的.)我认为没有任何证据表明这是不应该"工作的情况.这看起来很像他们的一个还不行"的案例.(不幸的是,几乎不可能让 Apple 确认这些情况之间的区别.)Array

可以是变量类型(其中 Array 不能)这一事实表明他们已经在这方面做了一些工作,但是 Swift 元类型有很多尖锐的边缘和未实现的情况.我认为您不会得到比这更好的为什么"答案.因为编译器不允许."(不满意,我知道.我的整个 Swift 生活......)

It's yet another case of metatypes. Swift really wants you to get to a concrete type for most non-trivial things. [P] isn't a concrete type (you can't allocate a block of memory of known size for P). (I don't think that's actually true; you can absolutely create something of size P because it's done via indirection.) I don't think there's any evidence that this is a case of "shouldn't" work. This looks very much like one of their "doesn't work yet" cases. (Unfortunately it's almost impossible to get Apple to confirm the difference between those cases.) The fact that Array<P> can be a variable type (where Array cannot) indicates that they've already done some work in this direction, but Swift metatypes have lots of sharp edges and unimplemented cases. I don't think you're going to get a better "why" answer than that. "Because the compiler doesn't allow it." (Unsatisfying, I know. My whole Swift life…)

解决方案几乎总是把东西放在一个盒子里.我们制作了一个类型橡皮擦.

The solution is almost always to put things in a box. We build a type-eraser.

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 来更自动地做同样的事情.

When Swift allows you to do this directly (which I do expect eventually), it will likely just be by creating this box for you automatically. Recursive enums had exactly this history. You had to box them and it was incredibly annoying and restricting, and then finally the compiler added indirect to do the same thing more automatically.

这篇关于协议不符合自身?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆