I don't think you can do that in an ideal way yet. I saw there was some talk about "opening existentials" here, but if you're a Swift beginner you probably don't want to read that. It makes me dizzy and I've been using Swift for a while.
If you really need a list of Cats with different type params, one possibility is to create a "type erased" version of a Cat...
struct AnyCat {
let cat: Any
let eatFood: () -> Void
let eat: (Any) -> Void
let getFood() -> Any
init<T>(_ cat: Cat<T>) {
self.cat = cat
self.eatFood = { cat.eat(cat.food) }
self.eat = { anyFood in cat.eat(anyFood as! T) }
self.getFood = { cat.food }
}
var food: Any { getFood() }
}
var cats = [AnyCat(Cat<Int>()), AnyCat(Cat<String>())]
for cat in cats {
cat.eatFood()
}
Disclaimer: I did not put that in Xcode. There may be typos or mistakes, but I hope it shows the idea. In the init of the AnyWhatever, you can create closures that know about T, cast from Any to T, etc., in order to create properties and methods of the AnyCat as needed.