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

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

问题描述

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

  protocol P {} 
struct S:P {}

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

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

让结果:[S] = arr.test()
P
不符合协议

> P (或者在更高版本的Swift中,不支持'使用'P'作为符合协议'P'的具体类型。)



为什么不呢?不知何故,这感觉就像是一个语言漏洞。我意识到这个问题源于将 arr 数组声明为协议类型的数组,但这是不合理的事情吗?我认为协议在那里确实有助于为结构提供像类型层次结构一样的东西?解析方案

编辑:工作18个月w / Swift,另一个主要版本(提供了一个新的诊断),以及来自@AyBayBay的评论让我想重写这个答案。新的诊断是:


不支持使用'P'作为符合协议'P'的具体类型。


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

 扩展数组元素:P {
元素== P 自 P 以后不适用<>

不被视为 P 的具体符合性。 (下面的放入盒子解决方案仍然是最通用的解决方案。)






旧答案: p>

它是元类型的又一例子。 Swift 真的 希望你得到一个具体类型的大多数不平凡的东西。 [P] 不是一个具体类型(您不能为 P >分配一个已知大小的内存块) )(我不认为这是真的,你可以绝对地创建大小 P ,因为通过间接方式完成)。我不认为有任何证据表明这是一个不应该的工作案例。这看起来非常像他们的不工作案件之一。 (不幸的是,让Apple确认这些情况之间的区别几乎是不可能的。) Array< P> 可以是变量类型(其中 Array 不能)表明他们已经在这个方向上做了一些工作,但是Swift元类型有很多尖锐的边缘和未实现的情况。我不认为你会得到比这更好的为什么的答案。 因为编译器不允许它。 (Unsatisfying,我知道,我的整个Swift生活......)

解决方案几乎总是把东西放在一个盒子里。我们构建一个类型擦除器。

  protocol P {} 
struct S:P {}

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

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

让arr = AnyPArray([S()])
让结果:[S] = arr.test()

当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()

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

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?

解决方案

EDIT: 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:

"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 {

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


Old Answer:

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()

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天全站免登陆