【问题标题】:Limitation with classes derived from generic classes in swiftswift中从泛型类派生的类的限制
【发布时间】:2014-06-10 10:13:41
【问题描述】:

我正在尝试从泛型类派生我的类:

class foo<T> {}
class bar : foo<Int> {}

但是这段代码编译失败,报错:

从泛型类派生的类也必须是泛型的

如何避免这种限制?有可能吗?

【问题讨论】:

  • 不,不可能。
  • 如此泛型在 swift 中几乎无法使用
  • 不正确,它只是与其他语言中的泛型设计不同。
  • @ssgreg,请参阅我的“穷人解决方案”来解决您的问题。
  • @ssgreg 我不得不同意这是非常严重的。

标签: class generics swift


【解决方案1】:

Ssreg,

不幸的是,这是official

你可以继承一个泛型类,但子类也必须是一个 泛型类。

让我们希望 Apple 在未来的版本中解决这个问题。

同时,让我们将此视为利用 aggregation 而不是子类化的机会。

注意:

作为穷人版本的解决方案,可以使用typealias

class foo<T> {}
class bar<Int> : foo<Int> {}
typealias Bar = bar<Int>

这样,其余的代码就可以像 Apple 已经解决问题一样编写了。

【讨论】:

  • 您似乎在引用文档,您能确认一下吗?我在您的链接(或“类型”部分)中找不到该段落。我想知道他们是否更改了文档和可能的意图。
  • 嘿@chrisco,我刚刚在b6中尝试过:没有雪茄,编译器抱怨。
  • 对,我在 B6 中也注意到了。但是文档 - 那是直接引用吗,因为我现在看不到那段?
  • 请注意,当您编写 class bar&lt;Int&gt; : foo&lt;Int&gt; {} 时,Int 成为泛型类型的占位符,覆盖实际的 swift Int 类型。当您尝试在类中使用 Int 的属性时,这将生成非常有趣的错误消息。最好在子类中使用未使用的泛型类型的 hpique 解决方案,并将基类绑定到真正的 Int 类型(或想要的)
  • 相反我在做:class bar&lt;T:Int&gt; : foo&lt;Int&gt; {}
【解决方案2】:

我遇到了同样的问题,我找到了解决方案!

class SomeType {
}
class Foo<T> {
}
class Bar<T: SomeType>: Foo<T> {
}

现在你可以这样做了:

let bar = Bar()

这会将 Bar 的类型默认为 SomeType。唯一的缺点是您只能对“可子类化”类型执行此操作。所以对于Int 这将不起作用。

【讨论】:

  • 这确实有效,但有轻微的代码气味。很好的发现。
  • 只是想以您的发现为基础并提出可能的修改建议。我通过建立您的答案来声明一个类public final class NonGenericSubclass {} 取得了成功,然后在您上面的示例的基础上,我会像这样声明Barclass Bar&lt;T : NonGenericSubclass&gt; : Foo&lt;Int&gt; { ... }。这样,我得到了将 Foo 类型化为 int 的所有好处,但我仍然可以像 Bar 不是通用的一样进行初始化。此外,因为NonGenericSubclass 被声明为final,所以它不能被子类化,所以任何声明泛型类型的类都可以认为它对于所有意图和目的都是非泛型的。很好的发现!
【解决方案3】:

在 Swift 2 中,可以对泛型类进行子类化:

class Something {}

class Base<T> {}

class Fancy : Base<Something> {}

【讨论】:

  • 是否有关于此的初步文档/博客引述可供参考?
  • 我没找到。我在操场上试试。
  • 您没有将泛型子类化,而是将具体化的泛型子类化为具体类型。这里的对象是class Fancy : Base&lt;T&gt;。这就是@Tom van Zummeren 的答案看起来正确的原因
【解决方案4】:

typealiassolution 的替代方法是从字面上理解文档:

你可以继承一个泛型类,但子类也必须是一个 泛型类。

因此我们将子类设为泛型类,但属于另一种我们不用于任何用途的类型。

class foo<T> {

    func doSomething(t:T) -> T {
        return t;
    }
}

class bar<S> : foo<Int> {

    override func doSomething(t:Int) -> Int {
        return t * t;
    }
}

let b : bar = bar<AnyObject>()
b.doSomething(5) // 25 instead of 5

我更喜欢这种使用typealias 的方法,因为它不会用其他类型污染命名空间。如果子类 (bar) 是 publicinternal,这一点尤其重要。

编辑

文档不再包含关于泛型子类限制的短语。希望这意味着 Apple 计划早日改变这一点。

【讨论】:

  • 使用 Beta 6 进行了表面测试。
  • 有趣的是他们如何围绕编译器限制设计语言,而不是反之亦然..
  • 这似乎可行,但用typealias bar = bar&lt;AnyObject&gt; 整理它不会
  • 我建议使用另一个名称创建中间体,以便您可以将 typealias 与上述技术一起使用。\n 例如:class GenericBase {}\n class _ExtendBase : GenericBase { }\n 类型别名 ExtendBase = _ExtendBase
【解决方案5】:

现在正式支持:

class Foo<RelatedType> {
    var object: RelatedType? = nil

    func myFunction(param: RelatedType) -> RelatedType? {
        return nil
    }
}

class Bar: Foo<String> {
    override func myFunction(param: String) -> String? {
        return self.object
    }
}

【讨论】:

    猜你喜欢
    • 2014-03-22
    • 1970-01-01
    • 2011-10-09
    • 2010-10-22
    • 2012-09-08
    • 2011-05-24
    • 2015-01-26
    • 2010-10-22
    • 1970-01-01
    相关资源
    最近更新 更多