为什么此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个月,Swift是另一个主要版本(提供新的诊断),并且@AyBayBay的评论使我希望重写此答案。新的诊断是:
“不支持将“ P”用作符合协议“ P”的具体类型。”
这实际上使整个事情变得更加清晰。此扩展名:
extension Array where Element : P {
Element == P
由于P
不能视为的具体符合,因此不适用于P
。(下面的“放在盒子里”解决方案仍然是最通用的解决方案。)
旧答案:
这是元类型的另一种情况。 斯威夫特(Swift) 确实(我不认为这是真的,您可以绝对创建大小的东西,
希望您对大多数不重要的事情都采取具体的态度。[P]
不是具体类型(您不能为分配大小已知的内存块P
)。P
因为它是通过间接完成的。)我不认为有任何证据表明这是“不应该”工作的情况。这看起来很像是他们的“不起作用”案例之一。(不幸的是,要让Apple确认这两种情况之间的区别几乎是不可能的。)事实Array<P>
可能是变量类型(其中Array
不能)表示他们已经朝这个方向做过一些工作,但是Swift元类型具有很多锋利的边缘和未实现的案例。我认为您不会得到比这更好的“为什么”答案。“因为编译器不允许。”
(不满意,我知道。我整个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
了自动执行相同功能的功能。