在swift中继承专门的泛型类

时间:2015-07-30 15:44:06

标签: swift generics override

我有一个基于AnyObject的泛型类DataSource。 使用下标函数从缓存中提取一些项目。

当我作为DataSource的子类时,下标函数停止被认为是覆盖,随后在类型为SpecialDataSource的对象上调用它将调用超类版本。

class DataSource<T: AnyObject>: NSObject {
    var cache: [T]?

    subscript(idx: Int) -> T? {
        if let hasStash = cache {
            if idx < hasStash.count{
                return hasStash[idx]
            }
        }
        return nil
    }
}


class SpecialDataSource<T> : DataSource<NSNumber> {
//The following declaration will generate:
//subscript does not override any subscript from its superclass

    override subscript(idx: Int) -> T? {
        if let hasStash = cache {
            if idx < hasStash.count{
                return hasStash[idx] as? T
            }
        }
        return nil
    }

}

在Playground中进行实验后,我发现如果SpecialDataSource声明是这样的话,就不会发生这种情况:

class SpecialDataSource<T> : DataSource<T>

我需要子类基于一个公共对象,所以我可以将它们中的一些填充到一个同构数组中。

因此该声明不提供该选项。

当我收到此错误时,听起来DataSource<NSNumber>完全是不同的超类。

任何想法在这里出错了?我试图理解为什么我的SpecialDataSource似乎无法覆盖这个函数。

===============目前的解决方案===========

我能够解决这个问题的唯一方法是将下标的返回类型专门化为NSNumber,实际上覆盖确实完成了这项工作。

不确定是否有更好的解决方案。请告诉我。我很乐意尝试一下。

class SpecialDataSource2<T: NSNumber> : DataSource2<NSNumber> {
    override subscript(idx: Int) -> NSNumber? {
        if let hasStash = cache {
            if idx < hasStash.count{
                return hasStash[idx] as? T
            }
        }
        return nil
    }

}

2 个答案:

答案 0 :(得分:0)

DataSource<NSNumber>确实是一个不同的超类。生成不同的代码!

您是否真的有意义的是,您要专门使用父类来使用NSNumber。什么是更深层的意图/目标?如果您在子级和父级中都遵循T模式会出现什么问题?

假设父类有另一个使用xyz的方法T。那么现在已经NSNumber绑定了,xyz期望NSNumber。当然,任何子类都继承xyz方法。但是现在假设您的子类用NSString实例化了T.对于xyz的实例,编译器应该对方法SpecialDataSource做什么?你看到了固有的冲突吗?

As&#34;神奇灵活&#34;仿制药,它们实际上有很多非常具体的规则。

答案 1 :(得分:0)

一个选项可能是定义子类,如下所示:

class SpecialDataSource<T, U> : DataSource<T> { ... }

这增加了一些复杂性 - SpecialDataSource现在需要两种通用类型。

但它也增加了灵活性。您可以拥有DataSource<NSNumber>DataSource<NSWhateverYouWant>的超类。

另外,我相信你的子类的下标函数看起来像这样:

subscript(idx: Int) -> U? {
    if let hasStash = cache {
        if idx < hasStash.count{
            return hasStash[idx] as? U
        }
    }
    return nil
}

...并且没有必要覆盖(我不在我可以测试它的地方。)