【问题标题】:Swift generic nestingSwift 泛型嵌套
【发布时间】:2021-06-22 13:31:21
【问题描述】:

我想将具有泛型的子类转换为超类,但它不起作用。真不知道问题出在哪里?

class People: NSObject {}
class Teacher: People {}
class BaseClass<T: People>: NSObject{
    init(_ model: T) {
        super.init()
        self.model = model
    }
    var model: T?
}
class SubClass<U: People>: BaseClass<U> {
    override init(_ model: U) {
        super.init ( model)
        self.subModel = model
    }
    var subModel: U?
}
class Tools: NSObject {
    static func transClass<M: People, T: BaseClass<M>>() -> T {
        let o = SubClass(Teacher()) as! T
        return o
    }
}
_ = Tools.transClass()

问题补充

感谢@RobNapier 的回答!这对我有点帮助。 我问这个问题是因为我想实现这样的代码

假码:

class BaseCellModel: NSObject{}

class BaseTableCell<M: BaseCellModel>: UITableViewCell{
    func setCellData(_ data: M){}
}

class BaseTableViewDelegate: NSObject, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    var dataSourceArr: [BaseCellModel] = [BaseCellModel]()
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return CellTools.getCellWith(tableView: tableView, indexPath: indexPath, model: dataSourceArr[indexPath.row])
    }
}

class CellTools {
    static func getCellWith(tableView: UITableView, indexPath: IndexPath, model: BaseCellModel) -> BaseTableCell<BaseCellModel> {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! BaseTableCell<BaseCellModel>
        cell.setCellData(model)
        return cell
    }
}

但是当我得到一个继承自 BaseTableCell 的 SubTableCell 时,代码正在运行到

let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! BaseTableCell&lt;BaseCellModel&gt;

出错了。

不管怎样,非常感谢。

(但我想知道是否有更好的方法可以达到同样的效果。)

【问题讨论】:

    标签: swift generics


    【解决方案1】:
        static func transClass<M: People, T: BaseClass<M>>() -> T {
            let o = SubClass(Teacher()) as! T
            return o
        }
    

    这个函数说

    • 调用者可以选择任何类型M,只要M 具有People 作为超类,并且
    • 调用者可以选择任何类型的T,只要T 具有BaseClass&lt;M&gt; 作为超类,并且
    • 该函数将返回调用者选择的类型T的实例。

    但这不是函数的作用。该函数始终创建一个SubClass&lt;Teacher&gt;,即使M 不是Teacher 并且T 不是SubClass&lt;Teacher&gt;。然后你尝试将SubClass&lt;Teacher&gt; 强制转换为T,这在运行时会失败,除非T 恰好是一个以SubClass&lt;Teacher&gt; 作为超类的类型。

    我不知道你应该做什么,因为我不知道你在这里真正想要完成什么。

    【讨论】:

    • 非常感谢!我知道你的意思。但是我不明白的是SubClassBaseClass 的子类而TeacherPeople的子类,我觉得是像多态一样的实现,像aString as! NSObject,我错了吗?
    【解决方案2】:

    鉴于你的 cmets 去抢劫 Mayoff,你想要返回的总是BaseClass&lt;People&gt; 的子类型,在这种情况下你的意思是:

    static func transClass() -> BaseClass<People> {
        let o = SubClass<People>(Teacher())
        return o
    }
    

    您需要在此处显式传递&lt;People&gt;,因为BaseClass&lt;Teacher&gt; 不是BaseClass&lt;People&gt; 的子类型。 Generics are not covariant.SubClass&lt;People&gt;BaseClass&lt;People&gt; 的子类型。这是一个正常的类继承关系。

    您可以通过避免使用临时变量来使其更易于编写。类型推断将为您完成工作:

    static func transClass() -> BaseClass<People> {
        SubClass(Teacher())
    }
    

    rob mayoff 说得最好,但重申一下,您当前的代码表明 调用者 可以决定 M 是什么,并且调用者可以要求 any 人的子类型。你不是那个意思。

    请注意,您通常应该避免这种嵌套继承 + 泛型。做对是非常复杂和棘手的。一般来说,如果可能,您应该更喜欢简单(非关联类型)协议而不是类继承。

    (也就是说,看看你在这里所做的事情,我有点怀疑具有关联类型和扩展的协议更可能是你想要的。我们必须看看你为什么想要 model 和 @ 987654332@这里。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-27
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-09
      • 2014-06-03
      • 1970-01-01
      相关资源
      最近更新 更多