为什么在Swift中向下转换数组项?

问题描述 投票:0回答:2

如果已知数组项的子类,为什么我必须在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 :)确定子类,但是在访问该子类中的成员时却无法推断出它?是一个错误,还是一个历史遗留物,还是我缺少了什么?

swift downcast
2个回答
1
投票

简单的答案是,一旦声明了类型为B的数组,编译器就会将该数组中的所有元素都视为类型为B,并且不会根据存在的任何子类自动推断方法。似乎您想知道为什么编译器/数组不够聪明,无法确定let声明的数组的类,而在理论上可以做到。我不确定许多语言是否支持该功能,无论如何您都可以像您一样通过将其拆开来完成相同的操作,因为在这种情况下您知道它。


0
投票

快速数组是单个类型。数组类型的项目的集合

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.