创建返回泛型的工厂方法
Creating a factory method returning generic
我有一个摘要class
这样定义:
class BaseCoordinator<ResultType>
其他类继承自这一个eg.
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<T>
,但我讨厌这种强制向下转换(并且返回 ?
也不能让我满意,因为我 100% 确定我将有一个正确的默认对象),因为我希望确保 至少 将返回一个默认值 Coordinator
。
感觉就像我错过了什么,但我真的不知道那是什么。是否真的可以制作这样的工厂方法,或者 Swift 泛型是否受限?
您可能想尝试 as?
而不是 as!
。前者产生一个可选的,我。 e.如果转换不成功,结果将为 nil。这样你就可以安全地进行转换,而无需强制执行任何操作。
T
必须在编译时有一个预定义的类型。因此,您不能通过返回具有不同 ResultType
的不同协调器来使用 makeCoordinator()
的实现来选择 T
。
在这种情况下,调用者可以选择要分配给 T
的值,这可能会破坏函数。例如,以下两个调用将是完全有效的:
let coordinator: BaseCoordinator<Void> = makeCoordinator()
let coordinator: BaseCoordinator<[Int: [String]]> = makeCoordinator()
将 [Int: [String]]
用作通用类型没有意义,但它仍然是可能的。根据您在函数调用时选择的泛型类型,转换可能有效或无效,这就是强制转换可能导致崩溃的原因。
按照 Tom E 的建议,可选的强制转换可以解决潜在的崩溃问题,但仍然无法解决此问题。
因此,如果不使用包装类型擦除 ResultType
到 Any
,您就不能为此使用工厂模式,这将破坏泛型的目的。
如果你想要类型安全,你必须为你想要实例化的 BaseCoordinator
的每个子类创建一个工厂方法,或者只是手动调用它们的初始化器。
我有一个摘要class
这样定义:
class BaseCoordinator<ResultType>
其他类继承自这一个eg.
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<T>
,但我讨厌这种强制向下转换(并且返回 ?
也不能让我满意,因为我 100% 确定我将有一个正确的默认对象),因为我希望确保 至少 将返回一个默认值 Coordinator
。
感觉就像我错过了什么,但我真的不知道那是什么。是否真的可以制作这样的工厂方法,或者 Swift 泛型是否受限?
您可能想尝试 as?
而不是 as!
。前者产生一个可选的,我。 e.如果转换不成功,结果将为 nil。这样你就可以安全地进行转换,而无需强制执行任何操作。
T
必须在编译时有一个预定义的类型。因此,您不能通过返回具有不同 ResultType
的不同协调器来使用 makeCoordinator()
的实现来选择 T
。
在这种情况下,调用者可以选择要分配给 T
的值,这可能会破坏函数。例如,以下两个调用将是完全有效的:
let coordinator: BaseCoordinator<Void> = makeCoordinator()
let coordinator: BaseCoordinator<[Int: [String]]> = makeCoordinator()
将 [Int: [String]]
用作通用类型没有意义,但它仍然是可能的。根据您在函数调用时选择的泛型类型,转换可能有效或无效,这就是强制转换可能导致崩溃的原因。
按照 Tom E 的建议,可选的强制转换可以解决潜在的崩溃问题,但仍然无法解决此问题。
因此,如果不使用包装类型擦除 ResultType
到 Any
,您就不能为此使用工厂模式,这将破坏泛型的目的。
如果你想要类型安全,你必须为你想要实例化的 BaseCoordinator
的每个子类创建一个工厂方法,或者只是手动调用它们的初始化器。