我怎样才能让 2 个泛型使用相同的 T 类型

How can I have 2 generics use the same T type

假设我有一个具有以下类型的视图控制器工厂:

protocol ViewFactoryType {
  associatedtype T
  func create(for scene: T) -> UIViewController
}

final class ViewFactory<T>: ViewFactoryType {
  func create(for scene: T) -> UIViewController {
    return .init()
  }
}

我还有一个导航路由器,型号如下:

protocol RouterType {
  associatedtype T
  func navigate(to target: T, using transition: Transition)
}

我想做的是创建一个 RouterType 的实例并传递它和一个 ViewFactory.

的实例

两种通用 T 类型实际上将使用相同的 Scene 类型。

我尝试按如下方式创建该路由器:

final class AppRouter<T>: RouterType {

  private let viewControllerFactory: ViewFactoryType
  private let navigationController: UINavigationController

  public init(navigationController: UINavigationController, viewControllerFactory: ViewFactoryType) {
    self.navigationController = navigationController
    self.viewControllerFactory = viewControllerFactory
  }

  public func navigate(to target: T, using transition: Transition) {
    routeTo(viewControllerFactory.create(for: target), transition: transition)
  }

  private func routeTo(_ viewController: UIViewController, transition: Transition) {
    switch transition {
    case .push: navigationController.pushViewController(viewController, animated: true)
    case .present: navigationController.present(viewController, animated: true)
    case .replace: navigationController.setViewControllers([viewController], animated: false)
    }
  }
}

但是这会产生错误:

Protocol 'ViewFactoryType' can only be used as a generic constraint because it has Self or associated type requirements

Member 'create' cannot be used on value of protocol type 'ViewFactoryType'; use a generic constraint instead

我可以通过使用扩展来稍微解决这个问题:

final class AppRouter<T> {

  private let viewControllerFactory: ViewFactoryType
  private let navigationController: UINavigationController

  public init(navigationController: UINavigationController, viewControllerFactory: ViewFactoryType) {
    self.navigationController = navigationController
    self.viewControllerFactory = viewControllerFactory
  }

  private func routeTo(_ viewController: UIViewController, transition: Transition) {
    switch transition {
    case .push: navigationController.pushViewController(viewController, animated: true)
    case .present: navigationController.present(viewController, animated: true)
    case .replace: navigationController.setViewControllers([viewController], animated: false)
    }
  }
}

extension AppRouter: Router where T == Scene {
  func route(to target: Scene, as transition: Transition) {

  }
}

但是工厂方法没有正确的类型如果我也添加了它func route(to target: Scene, as transition: Transition)

您不能以这种方式传递 associatedtype 属性。编译器不了解它们应该如何关联或您希望如何使用它们。

您可以重构您的 AppRouter 以接受代表它应该期望的 ViewFactoryType 的类型。

final class AppRouter<T, R> {

  private let viewControllerFactory: R
  private let navigationController: UINavigationController

  public init(navigationController: UINavigationController, viewControllerFactory: R) {
    self.navigationController = navigationController
    self.viewControllerFactory = viewControllerFactory
  }

  private func routeTo(_ viewController: UIViewController, transition: Transition) {
    switch transition {
    case .push: navigationController.pushViewController(viewController, animated: true)
    case .present: navigationController.present(viewController, animated: true)
    case .replace: navigationController.setViewControllers([viewController], animated: false)
    }
  }
}

extension AppRouter: RouterType where T == Scene, R == ViewFactory<T> {
  func navigate(to target: Scene, as transition: Transition) {
    let viewController = viewControllerFactory.create(for: target)
    routeTo(viewController, transition: transition)
  }
}

您现在可以通过传递正确的类型来创建实例

    let viewControllerFactory = ViewFactory<Scene>()
    let router = AppRouter<Scene, ViewFactory<Scene>>(navigationController: navigationController, viewControllerFactory: viewControllerFactory)