【问题标题】:Creating a factory method returning generic创建返回泛型的工厂方法
【发布时间】:2017-08-29 11:50:28
【问题描述】:

我有一个 抽象 class 这样定义:

class BaseCoordinator<ResultType>

其他类继承自这个例如。

final class AppCoordinator: BaseCoordinator<Void>
final class AuthFlowCoordinator: BaseCoordinator<AuthFlowCoordinationResult>
final class MainFlowCoordinator: BaseCoordinator<Void>

现在我想创建一个 factory 方法。我猜它的签名应该是这样的:

func makeCoordinator<T>() -> BaseCoordinator<T>

但是,当然,我会收到这样的错误:

Cannot convert return expression of type 'AppCoordinator' to return type 'BaseCoordinator<T>'

Xcode 建议我添加as! BaseCoordinator&lt;T&gt;,但我讨厌这种强制向下转换(返回? 也不能让我满意,因为我100% 确定我会有一个正确的默认对象),因为我希望保证至少会返回默认的Coordinator
感觉好像我错过了什么,但我真的不知道它是什么。是否真的可以制作这样的工厂方法,或者 Swift 泛型是否有限?

【问题讨论】:

  • 你是如何实现工厂方法的?你只是检查T是什么并返回相应子类的实例吗?

标签: swift generics inheritance factory


【解决方案1】:

T 在编译时必须有一个预定义的类型。因此,您不能通过返回具有不同ResultTypes 的不同协调器来使用makeCoordinator() 的实现来选择T

在这种情况下,调用者可以选择他想要分配给T 的值,这可能会破坏函数。例如,以下两个调用将是完全有效的:

let coordinator: BaseCoordinator<Void> = makeCoordinator()
let coordinator: BaseCoordinator<[Int: [String]]> = makeCoordinator()

[Int: [String]] 用作泛型类型是没有意义的,但它仍然是可能的。根据您在函数调用时选择的泛型类型,强制转换可能会起作用,这就是强制转换可能会导致崩溃的原因。

按照 Tom E 的建议,可选的演员阵容可以解决潜在的崩溃问题,但仍无法解决此问题。

因此,如果不使用包装器类型将 ResultType 擦除到 Any,则不能为此使用工厂模式,这会破坏泛型的目的。

如果你想要类型安全,你必须为你想要实例化的BaseCoordinator 的每个子类创建一个工厂方法,或者手动调用它们的初始化程序。

【讨论】:

    【解决方案2】:

    您可能想尝试as? 而不是as!。前者产生一个可选的,i。 e.如果强制转换不成功,结果将为 nil。这样一来,您就可以安全地施放,而无需强制执行任何操作。

    【讨论】:

    • 我知道我可以投射,但我必须返回 Optional。
    • 好吧,如果你“100% 确定我会有一个正确的默认对象”,那么我会说使用 as! 强制转换返回类型是完全合理的。
    猜你喜欢
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多