我怎样才能让 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)
假设我有一个具有以下类型的视图控制器工厂:
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)