编辑:这在Swift 3中运行得非常好,我们现在都应该使用它们了。)
如果我有两个协议X
和Y
Y
实现X
,为什么我不能将Y
数组分配给[X]
类型为protocol X { }
protocol Y: X { }
// Make a test array of Y
extension String: Y { }
let a: [Y] = [ "Hello" ]
// Make it into an array of X - this works absolutely fine
let b: [X] = [ a[0] as X ]
// Why won't this cast work?
let c: [X] = a as [X]
的变量?
更奇怪的是,我可以将它逐个转换为X数组,编译得很好。
c
我认为,鉴于Y做了X可以做的所有事情,这个任务应该没问题(是的,我丢失了一些类型信息,但它至少应该编译!)
有什么想法吗?
编辑:current answer指出,如果你使用可变数组,这是一件危险的事情 - 我现在还没有做到但是现在做了:)但是,如果我的数组都是不可改变为什么不会让Swift发生这种情况?即使var c = a as [X]
是一个可变数组(即a
),为什么不会将Swift复制它,让UITableViewCell extension
完好无损?
答案 0 :(得分:7)
这不起作用,因为它可能会产生一些问题。例如:
var squares: Array<Square> = Array<Square>()
(squares as [Shape]).append(Circle())
现在我们在Square of Squares中有一个圆圈。我们不想要那样,所以编译器不允许我们这样做。在Scala等其他语言中,您可以指定泛型为covariant
,contravariant
或invariant
。
如果Swift允许您使用协变泛型,则Array<Square>
将是Array<Shape>
的子类型。
如果使用逆转,Array<Square>
将是Array<Shape>
的超类型(!)。
但是当使用不变泛型时,两者的子类型都不是。
在您的情况下,最简单的方法可能就是:
let c = a.map{$0 as X}
现在c
的类型为[X]
。
有关类型差异及其访问原因的详细信息,请访问this wiki page。
编辑:经过进一步来回,似乎真正的问题是,协议允许默认实现,因此可能会导致问题。使用类时,您的代码将完美编译。以下是一些可能导致协议出现问题的代码:
protocol Shape {
func surfaceArea() -> Double
}
extension Shape {
func surfaceArea() -> Double {
return 0.0
}
}
protocol Circle : Shape {
func getRadius() -> Double
}
extension Circle {
func surfaceArea() -> Double {
return getRadius() * getRadius() * 3.14
}
}
现在,当我们在这两个协议之间进行upcast时,surfaceArea()
方法返回不同的值,而Swift不允许它。
使用类而不是协议尝试相同的事情,Swift在编译当前代码时没有遇到任何问题。对我来说,这是Swift团队的一个奇怪的决定,但我仍然认为减轻的最佳方法是使用
let c = a.map{$0 as X}