为什么可以';我不能在Swift中使用泛型类型的子类吗?

为什么可以';我不能在Swift中使用泛型类型的子类吗?,swift,generics,subclassing,Swift,Generics,Subclassing,为什么Swift不允许我将值Foo赋值给Foo类型的变量,其中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

为什么Swift不允许我将值
Foo
赋值给
Foo
类型的变量,其中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 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=goudaplater
有何不同呢?是否有任何情况下,如果它起作用,将是不安全的?这仅仅是当前版本Swift的一个限制吗?

您可以使用一种称为的技术来解决这个问题。基本上,您创建了一个“包装器”结构,它对泛型隐藏了底层类的细节。这并不理想,但它可以让你完成一些类似于你正在尝试做的事情

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"
class奶酪{
func doSomethingCheesy(){
打印(“我是奶酪”)
}
}
高达班:奶酪{
重写func doSomethingCheesy(){
打印(“我是gouda”)
}
}
结构奶酪{
让奶酪:奶酪
}
类容器{
init(对象:T){
self.object=对象
}
让对象:T
}
让奶酪=奶酪
让cheeseContainer:Container=Container(对象:AnyCheese(cheese:cheese))
设gouda=gouda()
让goudaContainer:Container=Container(对象:AnyCheese(cheese:gouda))
cheeseContainer.object.cheese.doSomethingCheesy()//打印“我是奶酪”
goudaContainer.object.cheese.doSomethingCheesy()//打印“我是gouda”

不是阳性,但你能将
拼盘
更改为
拼盘
(以及随后的
var food:T
init(food:T)
)?泛型在Swift中是不变的–在类型系统中,
拼盘
拼盘
是完全不相关的。如果要在它们之间进行转换,则需要编写代码来执行该转换
Array
只是一种特殊情况,编译器会在幕后施展一些魔法,以便为您执行此转换(参见示例)。相关(甚至可能重复?):这很相似,但我认为不一样。这个问题是关于协议的,而这是关于子类的。另外,这个问题是关于收藏的。罗布·纳皮尔(Rob Napier)的回答非常好,他在回答中展示了打字系统是如何崩溃的,但我正在努力将其应用到我的问题中。
如何让platter:platter=goudaplater
破坏类型系统?@ConfusedByCode对不起,我完全忘了回复你!事实上,我最近已经回答了。请让我知道这是否完全回答了你的问题:)我对你的答案投了赞成票,因为这是对类型擦除的一个很好的解释,我相信它会帮助找到这个问题的人。然而,我没有将其标记为已接受,因为我是在要求解释为什么斯威夫特会这样做,而不是寻找一个解决办法。我认为对我问题的评论可以重新整理成一个好的答案。
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"