[英]Swift - How to store in an Array subclasses of a generic type
所以,我有一個泛型(有限制)類和它的子類的許多子類,當它們是子類時具體的泛型類型。
我想將這些子類的實例存儲在一個數組中,這樣它們就可以迭代並以相同的方式處理所有這些子類,但顯然,沒有辦法將子類轉換為泛型超類。
以下是一些說明問題的代碼(您可以將其復制粘貼到操場中以查看結果):
// Lets create regular classes
class Fruit {
var text: String { return "I am some Fruit" }
}
class Apple: Fruit {
override var text: String { return "I am an Apple" }
}
class Orange: Fruit {
override var text: String { return "I am an Orange" }
}
// This obviously works:
let test1: Fruit = Apple()
let test2: Fruit = Orange()
// Let's create some generic class
class Tree<T: Fruit> {
let fruit: T
init(fruit: T) {
self.fruit = fruit
}
}
// Subclasses from the generic class (these work)
class AppleTree: Tree<Apple> {
convenience init() {
self.init(fruit: Apple())
}
}
class OrangeTree: Tree<Orange> {
convenience init() {
self.init(fruit: Orange())
}
}
// This works:
let tree: Tree<Fruit> = Tree(fruit: Apple())
tree.fruit.text // "I am an Apple"
// This works:
let appleTree1: Tree<Apple> = AppleTree()
appleTree1.fruit.text // "I am an Apple"
// This fails: "Cannot convert value of type 'AppleTree' to specified type 'Tree<Fruit>'
let appleTree2: Tree<Fruit> = AppleTree()
// This works:
let fruitArray: [Fruit] = [Apple(), Orange()]
// THIS IS MY GOAL:
// This fails: "Cannot convert value of type 'AppleTree' to specified type 'Tree<Fruit>'
let treeArray: [Tree<Fruit>] = [AppleTree(), OrangeTree()]
// Let's try with a generic subclass
class FruitTree<T: Fruit>: Tree<T>{}
// This works:
let genericTree: Tree<Fruit> = FruitTree(fruit: Apple())
// Let's try with a generic but more concrete subclass
class GenericOrangeTree<T: Orange>: Tree<T>{
convenience init() {
self.init(fruit: Orange() as! T)
}
}
// This works:
let genericOrangeTree1 = GenericOrangeTree(fruit: Orange())
let genericOrangeTree2 = GenericOrangeTree()
// This fails: Cannot invoke initializer for type 'GenericOrangeTree<Orange>' with an argument list of type '(fruit: Orange)'
let genericTree2: Tree<Fruit> = GenericOrangeTree(fruit: Orange())
// Again, this fails: "Cannot convert value of type 'GenericOrangeTree<Orange>' to specified type 'Tree<Fruit>'
let genericTreeArray: [Tree<Fruit>] = [GenericOrangeTree()]
我試圖做的是通過treeArray
變量在示例代碼中說明的。
我不明白為什么代碼失敗時會失敗。 我的直覺說這應該有效,我無法找到解決這個問題的方法。
TL; DR:我有一個帶有一些子類的Generic類,我想要一個填充了子類的Generic類的數組,但編譯器抱怨。
您正在混淆Generics實現之前和之后的類型層次結構。 使用泛型類/ func,您基本上可以設置一個在編譯時解析的模板(編譯器宏)。
如果你說
Generic<SubClass1>
Generic<SuperClass>
這些由編譯器解析為類型:
class Generic_SubClass1 {
let property : SubClass1
}
class Generic_SuperClass {
let property : SuperClass
}
在解析泛型之后,這兩種類型不共享基本類型,因此不能相互轉換。 它們是完全分開的。
不確定也沒試過,但也許這就是你想要的:
class GenericBase {
let property : SuperClass
}
class Generic<T: SuperClass> : GenericBase {
final var typedProperty : T {
get { return property as T }
set { property = T }
}
}
然后,您可以使用GenericBase
作為公共祖先,並使用動態類型來檢查子類。
PS:你的代碼有點難以理解,也許使用像'Fruit','Apple'和'Orange'這樣的東西 - 比'Superclass','Subclass1','Subclass2'更容易閱讀;-)
我認為你要找的是類型擦除。
例如,成像您有以下內容:
protocol ClassWithView {
associatedType: View: UIView
var view: View { get set }
}
class ConcreteWithView {
associatedType View = SubclassOfUIView
var view: SubclassOfUIView
}
// Somewhere this will fail because there is missing associated type information
var array: [ConcreteWithView]
通過類型擦除,您可以強制執行對陣列的任何訪問,只允許您訪問常見的UIView內容。 修改上面的內容如:
protocol AnyClassWithView {
var baseView: UIView
}
protocol ClassWithView: AnyClassWithView {
associatedType: View: UIView
var view: View { get set }
}
// Default implementation
extension AnyClassWithView {
var baseView: UIView {
return view as UIView
}
}
現在,在其他地方你可以定義數組:
var array: [AnyClassWithView]
哪個會成功,您只能使用.baseView
訪問UIView類型。 您可以向AnyClassWithView
定義添加內容並使用共享UIView
。
如果要訪問各個子類型,請在此上創建一個接受通用參數的函數,並且您應該能夠轉換以訪問子類型信息。
也許你可以定義一個名為FruitTree
的協議,它可以獲得一個Fruit並返回某種Fruit:
protocol FruitTree {
associatedType FruitKind
func getFruit() -> Fruit
func setFruit(FruitKind)
}
然后,定義類如下:
class AppleTree: FruitTree {
var apple Apple
typeAlias FruitKind = Apple
func getFruit() -> Apple {return apple}
func setFruit(Apple a} {apple = a}
}
class OrangeTree: FruitTree {
var orange Orange
typeAlias FruitKind = Orange
func getFruit() -> Orange { return orange}
func setFruit(Orange o) {orange= o}
}
let treeArray: [FruitTree] = [AppleTree(), OrangeTree()]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.