如果已知数组项的子类,为什么我必须在Swift中向下转换数组项?
> class B {let t: String = "-B-"}
> class B1:B {let t1: String = "-B1-"}
> class B2:B {let t2: String = "-B2-"}
> let bunch = [B(), B1(), B2()]
按预期:
> print(type(of:bunch))
Array<B>
已知数组每个元素的子类:
> for item in bunch {print(type(of:item))}
B
B1
B2
但是(如所记录的那样,我们无法访问该项目的子类成员,而我们必须进行降级:
> if bunch[1] is B1 {let b1 = bunch[1] as! B1; print(b1.t1)}
-B1-
因为这不起作用:
> bunch[1].t1
error: repl.swift:17:6: error: value of type 'B' has no member 't1'; did you mean 't'?
为什么Swift可以使用type(of :)确定子类,但是在访问该子类中的成员时却无法推断出它?是一个错误,还是一个历史遗留物,还是我缺少了什么?
简单的答案是,一旦声明了类型为B
的数组,编译器就会将该数组中的所有元素都视为类型为B
,并且不会根据存在的任何子类自动推断方法。似乎您想知道为什么编译器/数组不够聪明,无法确定let
声明的数组的类,而在理论上可以做到。我不确定许多语言是否支持该功能,无论如何您都可以像您一样通过将其拆开来完成相同的操作,因为在这种情况下您知道它。
快速数组是单个类型。数组类型的项目的集合
let bunch = [B(), B1(), B2()]
被推断为[B]
,因为B
是给定三个元素的“最近的公共超类”。因此,bunch[1]
具有类型B
,而不是B1
。这就是为什么bunch[1].t1
无法编译的原因。
当然,您可以在运行时使用type(of:)
打印数组元素的实际类型,或对照B1
进行检查。后者最好通过可选绑定来完成:
if let b1 = bunch[1] as? B1 {
print(b1.t1)
}