Why doesn't Swift allow me to assign value Foo<U>
to a variable of type Foo<T>
, where U is a subclass of T?
为什么Swift不允许我将值Foo 赋值给Foo
For example:
例如:
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
But why doesn't it work? You can assign to a variable an object that's a subclass of it's type, e.g.
但为什么不起作用?您可以为变量分配一个对象,该对象是其类型的子类,例如
let gouda = Gouda(smell: 6, hardness: 5, name: "Gouda", aged: false)
let cheese: Cheese = gouda
And you can add subclasses to collections:
您可以将子类添加到集合:
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)
So how is let platter: Platter<Cheese> = goudaPlatter
different? Are there any circumstances where it would be unsafe if it worked? Is it simply a limitation of the current version of Swift?
那么如何让拼盘:拼盘
1 个解决方案
#1
5
You can work around this using a technique called type erasure. Basically you create a "wrapper" struct which hides the underlying class detail from the generic. It's not ideal, but it allows you to accomplish something similar to what you're trying to do.
您可以使用称为类型擦除的技术解决此问题。基本上,您创建了一个“包装器”结构,它隐藏了泛型中的基础类详细信息。它并不理想,但它可以让你完成类似于你想要做的事情。
class Cheese {
func doSomethingCheesy() {
print("I'm cheese")
}
}
class Gouda: Cheese {
override func doSomethingCheesy() {
print("I'm gouda")
}
}
struct AnyCheese {
let cheese: Cheese
}
class Container<T> {
init(object: T) {
self.object = object
}
let object: T
}
let cheese = Cheese()
let cheeseContainer: Container<AnyCheese> = Container(object: AnyCheese(cheese: cheese))
let gouda = Gouda()
let goudaContainer: Container<AnyCheese> = Container(object: AnyCheese(cheese: gouda))
cheeseContainer.object.cheese.doSomethingCheesy() // prints "I'm cheese"
goudaContainer.object.cheese.doSomethingCheesy() // prints "I'm gouda"
#1
5
You can work around this using a technique called type erasure. Basically you create a "wrapper" struct which hides the underlying class detail from the generic. It's not ideal, but it allows you to accomplish something similar to what you're trying to do.
您可以使用称为类型擦除的技术解决此问题。基本上,您创建了一个“包装器”结构,它隐藏了泛型中的基础类详细信息。它并不理想,但它可以让你完成类似于你想要做的事情。
class Cheese {
func doSomethingCheesy() {
print("I'm cheese")
}
}
class Gouda: Cheese {
override func doSomethingCheesy() {
print("I'm gouda")
}
}
struct AnyCheese {
let cheese: Cheese
}
class Container<T> {
init(object: T) {
self.object = object
}
let object: T
}
let cheese = Cheese()
let cheeseContainer: Container<AnyCheese> = Container(object: AnyCheese(cheese: cheese))
let gouda = Gouda()
let goudaContainer: Container<AnyCheese> = Container(object: AnyCheese(cheese: gouda))
cheeseContainer.object.cheese.doSomethingCheesy() // prints "I'm cheese"
goudaContainer.object.cheese.doSomethingCheesy() // prints "I'm gouda"