简体   繁体   中英

Swift func with generic where constraint is a protocol which self conforms

I'm trying to write a static generic method which takes a protocol as an argument and register class instance in Swinject container as a protocol resolve. It's important that I could not register a module as a protocol it does not conforms to.

I wrote something like this:

/// RegisterableModule guarantee that conformer has `create()` method returning self

public extension RegisterableModule {

    static func registerModule<P>(asProtocol proto: P.Type,
                                  in container: Container) {
        container.register(proto, name: nil) { (resolver) -> P in
            return self.create()
        }
    }
}

It does not compile because obviously Self may be not conforming to P

I also tried to specify generic constraint using where :

  1. where Self: P does compile error "Type 'Self' constrained to non-protocol, non-class type 'P'"
  2. where self: P does multiple compiles error.
  3. where Self: P.Type does compile error "Type 'Self' constrained to non-protocol, non-class type 'P.Type'"
  4. where self: P.Type does multiple compile errors.

I also wonder if I can specify a constraint that P can be protocol only.

Unfortunatelly, there is no way (yet) in Swift to define requirement of conformance to generic parameters, or require parameter to be a protocol.

This is the reason why Swinject's type-forwarding API is not type safe . There is a "trick" that sort-of enables one to express a conformance requirement, however I'm not sure if it would be practical for your use-case:

extension RegisterableModule {

    static func registerModule<P>(
        asProtocol proto: P.Type, 
        in container: Container, 
        typeCheck: (Self) -> P
    ) {
        container.register(proto) { _ in self.create() as! P }
    }
}

MyModule.registerModule(
    asProtocol: MyProtocol.self, 
    in: container, 
    typeCheck: { $0 }
)

Can you try it, I just added P:SomeProtocol

public extension RegisterableModule {

    static func registerModule<P:SomeProtocol>(asProtocol proto: P.Type,
                                  in container: Container) {
        container.register(proto, name: nil) { (resolver) -> P in
            return self.create()
        }
    }
}

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