我有一个基类类型和一个子类类型,其中子类包括一个泛型类型。如果我以基类类型的形式存储了子类,但是我想将其类型强制转换回子类类型,那么Swift似乎不会允许我。
以下是我的意思的示例:
class Base {
}
class Next<T> : Base where T : UIView {
var view: T
init(view: T) {
self.view = view
}
}
let a: [Base] = [Next(view: UIImageView()), Next(view: UILabel())]
for item in a {
if let _ = item as? Next {
print("Hey!")
}
}
为什么"Hey!"
从未打印过?
编辑:
如果强制转换显示为 "Hey!"
,则打印:
if let _ item as? Next<UIImageView> ...
但仅适用于UIImageView类。
和
如果数组"Hey!"
中的一项为: a
将被打印
Next(view: UIView())
理想情况下,我不希望泛型转换时使用哪种类型,但是我意识到这可能是不可能的。
答案 0 :(得分:4)
通用Next<T>
是创建唯一的单独类的各种模板。 Next<UIView>
和Next<UIImageView>
是两种完全不相关的类型。
您可以将它们与协议结合起来:
class Base {
}
class Next<T> : Base where T : UIView {
var view: T
init(view: T) {
self.view = view
}
}
protocol NextProtocol { }
extension Next: NextProtocol { }
let a: [Base] = [Next(view: UIImageView()), Next(view: UILabel()), Base()]
for item in a {
if item is NextProtocol {
print("Hey!")
} else {
print("Only a Base")
}
}
输出:
Hey! Hey! Only a Base
通过定义诸如NextProcotol
的协议,所有从Next<T>
派生的类都应遵循,可以将它们称为一个组并将它们与从Base
派生的其他类区分开。
注意:要检查item
是否为类型,请使用is
而不是检查条件强制转换as?
是否有效。
答案 1 :(得分:0)
当我看到您的示例时,我期望它在编译过程中会失败。
似乎,只要为T指定一个具体的基类(在本例中为UIView),编译器就可以在Update Pallets SET CreatedDate = DATEADD(hour, -7, (Select CreatedDate from Pallets Where PalletNumber = 63))
或as
语句中推断该类。因此,当您键入is
时,编译器会理解item as? Next
Next`,因为UIView是一种具体类型。
如果使用协议而不是UIView,则此方法将无效。另外,仅使用item as?
而不是Next
(或Next<UIView>
)将在Next<concrete subclass of UIView>
或is
语句之外导致编译器错误。
答案 2 :(得分:0)
这是协议提供帮助的地方。
您需要一个虚拟协议来确认Next
并使用该虚拟协议检查您的商品类型。
因此,我们创建了一个虚拟协议以确认Next
并使用该协议比较items
。
代码将是这样的。
class Base {
}
class Next<T> : Base where T : UIView {
var view: T
init(view: T) {
self.view = view
}
}
protocol MyType {
}
extension Next: MyType {}
let a: [Base] = [Next(view: UILabel()), Next(view: UILabel())]
for item in a {
if let _ = item as? MyType {
print("Hey!")
}
}
UIView
是所有UIElements
的超类。
说这将成为真实的
if let _ = UILabel() as? UIView {print("yes") }
Next
不会确认UIView
,而是需要确认UIView
的内容,因此您不能使用UIView
的子项来检查它们是否为{ {1}},下一个没有确切类型,
这里我们使用上面的虚拟协议!