Swift 泛型:将类型参数约束到协议

Cod*_*256 5 generics type-parameter generic-constraints swift

如何指定泛型类型参数只能是协议(或符合该协议的协议),而不能是符合该协议的类?

例如:

import Foundation

@objc protocol MyProtocol {
    var name: String { get }
}

@objc protocol MySubProtocol: MyProtocol {
    func foo()
}

class MyImplementation: MySubProtocol {
    var name: String

    init(name: String) {
        self.name = name
    }

    func foo() {
        print("Foo! Name: \(self.name)")
    }
}

class InterfaceMaker<T: MyProtocol> {
    init() {}

    func makeInterface() -> NSXPCInterface {
        return NSXPCInterface(with: T.self) // Cannot convert value of type 'T.Type' to expected argument type 'Protocol'
    }


    func getProxy() -> T? {
        // Some magic in here involving `NSXPCConnection.remoteObjectProxy`
    }
}

InterfaceMaker<MySubProtocol>().makeInterface() // No error, as expected
InterfaceMaker<MyImplementation>().makeInterface() // No error, but should not work!
Run Code Online (Sandbox Code Playgroud)

如何指定泛型类型参数应该是协议?

我想限制T为仅符合(例如)的协议。但问题是,我不知道如何防止 T 成为一个类(例如)。MyProtocolMySubProtocolMyImplementation

我已经尝试过约束T.self(我试图使用where T.self : Protocol,但这导致了错误'self' is not a member type of 'T')。

那么我如何指定它T必须是符合的协议MyProtocol,而不是类如果这是不可能的,我至少可以指定 T 应该是任何协议吗?如果我需要制作仅类协议也可以。

作为MySubProtocol非泛型参数传递并不是想要的,因为我还希望能够使用该协议作为函数的类型InterfaceMaker.getProxy()。此外,让该函数简单地返回MyProtocol(换句话说,是非InterfaceMaker泛型的)也不是一种选择。

注意:为了完全清楚,我需要成为一个协议的原因T是我要将它传递给NSXPCInterface.init(with:),它需要 a Protocol(可以通过SomeProtocol.selfif SomeProtocolis获得@objc)。这意味着SomeProtocol.self.Type是或符合

如果这是不可能的,请给出完整的解释。还要提及未来的 Swift 版本是否有可能支持这一点。

编辑:另一种表达方式是,这T.self is AnyObject.Type永远不应该是真的。我宁愿在编译时检查这一点,而不是运行时检查或断言。

bar*_*ity 2

您可以检查是否符合所有类隐式符合的T协议,但不符合协议。AnyObject

所以,在InterfaceMaker

class InterfaceMaker<T: MyProtocol> {
    init() {}

    func makeInterface() -> NSXPCInterface {
        if T.self is AnyObject.Type {
           //  T is a class
        } else {
           return NSXPCInterface(with: T)
        }
    }


    func getProxy() -> T? {
        // Some magic in here involving `NSXPCConnection.remoteObjectProxy`
    }
}
Run Code Online (Sandbox Code Playgroud)