【发布时间】:2016-10-19 18:48:02
【问题描述】:
为什么 Swift 不允许我将值 Foo<U> 分配给 Foo<T> 类型的变量,其中 U 是 T 的子类?
例如:
class Cheese {
let smell: Int
let hardness: Int
let name: String
init(smell: Int, hardness: Int, name: String) {
self.smell = smell
self.hardness = hardness
self.name = name
}
func cut() {
print("Peeyoo!")
}
}
class Gouda: Cheese {
let aged: Bool
init(smell: Int, hardness: Int, name: String, aged: Bool) {
self.aged = aged
super.init(smell: smell, hardness: hardness, name: name)
}
override func cut() {
print("Smells delicious")
}
}
class Platter<Food> {
var food: Food
init(food: Food) {
self.food = food
}
}
let goudaCheese = Gouda(smell: 6, hardness: 5, name: "Gouda", aged: false)
let goudaPlatter = Platter(food: goudaCheese) //Platter<Gouda>
//error: cannot assign value of type 'Platter<Gouda>' to type 'Platter<Cheese>'
let platter: Platter<Cheese> = goudaPlatter
但为什么它不起作用?您可以为变量分配一个对象,该对象是其类型的子类,例如
let gouda = Gouda(smell: 6, hardness: 5, name: "Gouda", aged: false)
let cheese: Cheese = gouda
您可以将子类添加到集合中:
let plainCheese = Cheese(smell: 2, hardness: 5, name: "American")
let gouda = Gouda(smell: 6, hardness: 5, name: "Gouda", aged: false)
var cheeses: [Cheese] = [plainCheese]
cheeses.append(gouda)
那么let platter: Platter<Cheese> = goudaPlatter 有什么不同呢?是否有任何情况下如果它起作用会不安全?仅仅是当前版本 Swift 的限制吗?
【问题讨论】:
-
不是肯定的,但你能把
Platter<Food>改成Platter<T: Food>(然后是var food: T,init(food: T))吗? -
泛型在 Swift 中是不变的——在类型系统的眼中,
Platter<Gouda>和Platter<Cheese>完全不相关。如果要在它们之间进行转换,则需要编写代码来执行该转换。Array只是一个特例,编译器在幕后做了一些魔术,以便为您执行此转换(例如,参见 this Q&A)。 -
很相似,但我认为不一样。这个问题是关于协议的,而这是关于子类的。此外,这个问题专门针对收藏。 Rob Napier 的回答,他展示了类型系统将如何破坏,非常好,但我正在努力将它应用于我的问题。
let platter: Platter<Cheese> = goudaPlatter会如何破坏类型系统? -
@ConfusedByCode 抱歉,我完全忘记回复你了!实际上,我最近回答了a similar Q&A here。如果这现在完全回答了您的问题,请告诉我:)
标签: swift generics subclassing