简体   繁体   中英

Creating a factory method returning generic

I have an abstract class defined this way:

class BaseCoordinator<ResultType>

Other classes inherit from this one eg.

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

Now I want to create a factory method. I guess it's sugnature should look like:

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

But, of course, I get error like this one:

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

What Xcode suggests me is to add as! BaseCoordinator<T> as! BaseCoordinator<T> , but I hate this force downcasting (and returning ? isn't satisfying me either, as I'm 100% sure I'll have a correct default object), as I want assurance that at least a default Coordinator will be returned.
It feels like I'm missing something, but I really have no clue what is it. Is it actually possible to make such factory method, or is Swift generics limited?

T must have a predefined type at compile time. Therefore you cannot choose T using the implementation of makeCoordinator() by returning different coordinators with different ResultType s.

In this case, the caller can choose which value he wants to assign to T , potentially breaking the function. For example the following two calls would be perfectly valid:

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

It would not make sense to use [Int: [String]] as a generic type but it is still possible. Depending on the generic type you choose at the function call, the cast may work or not, which is why a force cast will likely lead to a crash.

An optional cast, as suggested by Tom E would fix the potential crash but it would still not resolve this problem.

Therefore you cannot use a factory pattern for this without erasing ResultType to Any using a wrapper type, which would defeat the purpose of generics.

If you want type safety, you have to create a factory method for each subclass of BaseCoordinator you want to instantiate or just call their initializers manually.

You might want to try as? instead of as! . The former yields an optional, ie the result will be nil if the cast doesn't succeed. This way you have a safe cast without the need of forcing anything.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM