【问题标题】:Swift Generic Classes and Extensions with Conditional Generics带有条件泛型的 Swift 泛型类和扩展
【发布时间】:2021-04-27 05:48:12
【问题描述】:

我有以下课程:

class MyClass<T: BaseClass> {

   let aThing = T()

   func someMethod() {
      configure()
   }
}

class SubTypeAOfBaseClass: BaseClass { ... }

class SubTypeBOfBaseClass: BaseClass { ... }

configure 中,我想根据其类型配置aThing。因此我创建了一个协议Configurable 和一个扩展:

protocol Configurable {
   func configure()
}

extension MyClass: Configurable where T == SubTypeAOfBaseClass {
  func configure() {
     print("Configuring SubTypeAOfBaseClass")
     aThing.doSomethingA()
  }
}

我得到的错误是在MyClass.someMethod 中我调用configure():“引用实例方法configure() 需要类型T 和SubTypeAOfBaseClass 是等价的。

添加以下扩展时的另一个错误:

extension MyClass: Configurable where T == SubTypeBOfBaseClass {
  func configure() {
     print("Configuring SubTypeBOfBaseClass")
     aThing.doSomethingB()
  }
}

错误更改为“调用实例方法配置中没有完全匹配”和行中

extension MyClass: Configurable where T == SubTypeBOfBaseClass {

我收到错误“MyClass 与可配置协议的一致性冲突,即使有不同的条件边界,也不能有多个一致性。”

应该工作,但显然我遗漏了一些东西,或者我对如何实现我想要的东西的理解是错误的。

【问题讨论】:

  • 抛开其他问题,如果T 既不是SubTypeAOfBaseClass 也不是SubTypeBOfBaseClass 怎么办?例如,如果 TBaseClass 会怎样?
  • 好问题。我没有答案。

标签: swift generics


【解决方案1】:

考虑TBaseClass,或者TAnotherSubclass 我定义为的情况

class AnotherSubclass : BaseClass {

}

会发生什么?当TAnotherSubclass 时,您还没有声明符合Configure

这里真的只有两个(不错的)选择。

  1. T 既不是SubTypeAOfBaseClass 也不是SubTypeBOfBaseClass 时,您希望configure 什么都不做
  2. 您只希望 MyClass&lt;SubTypeAOfBaseClass&gt;MyClass&lt;SubTypeBOfBaseClass&gt; 成为有效类型 - MyClass&lt;BaseClass&gt;MyClass&lt;AnotherSubclass&gt; 会导致编译器错误。

选择 2 在 Swift 中是不可能的。这需要类似于 sealed types in Java 或 Kotlin 的东西。

选择 1 可以这样完成:

class BaseClass {
    ...
    func configure() {
        
    }
}

class SubTypeAOfBaseClass: BaseClass {
    ...
    override func configure() {
        print("Configuring SubTypeAOfBaseClass")
        doSomethingA()
    }
}

class SubTypeBOfBaseClass: BaseClass {
    ...
    override func configure() {
        print("Configuring SubTypeAOfBaseClass")
        doSomethingB()
    }
}
class MyClass<T: BaseClass> {

   let aThing = T()

    func someMethod() {
        aThing.configure()
    }
}

您可能会注意到configure 的每个实现都已移至基类。如果你想在MyClass中实现它们,你必须手动检查类型:

class MyClass<T: BaseClass> {

   let aThing = T()

    func someMethod() {
        if let selfA = self as? MyClass<SubTypeAOfBaseClass> {
            selfA.configure()
        } else if let selfB = self as? MyClass<SubTypeBOfBaseClass> {
            selfB.configure()
        }
    }
}

extension MyClass where T == SubTypeAOfBaseClass {
  func configure() {
     print("Configuring SubTypeAOfBaseClass")
     aThing.doSomethingA()
  }
}
extension MyClass where T == SubTypeBOfBaseClass {
  func configure() {
     print("Configuring SubTypeBOfBaseClass")
     aThing.doSomethingB()
  }
}

这是因为您的代码中的第二个问题 - 泛型类型的不同参数化,MyClass&lt;SubTypeAOfBaseClass&gt;MyClass&lt;SubTypeBOfBaseClass&gt;,不能以不同方式遵守协议。不幸的是,这是 Swift 的一个限制。请参阅here 了解更多信息。

【讨论】:

  • 非常感谢您的回答。我需要在MyClass 中实现configure 并且不能在子类型中这样做。我实际上希望选择2。也许有一天。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多