Swift Generics:将类型参数约束为协议

时间:2017-12-10 21:12:23

标签: swift generics type-parameter generic-constraints

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

例如:

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!

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

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

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

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

MySubProtocol作为非泛型参数传递而不是我正在寻找的内容,因为我也希望能够将该协议用作{{1}的类型功能。此外,让该函数简单地返回InterfaceMaker.getProxy()(换句话说,让MyProtocol非通用)也不是一种选择。

注意:要完全清楚,我需要InterfaceMaker成为协议的原因是我要将其传递给T,这需要NSXPCInterface.init(with:) {1}}(如果ProtocolSomeProtocol.self,则可以SomeProtocol获取)。这意味着@objc符合或符合

如果无法做到这一点,请详细解释原因。还要提一下是否有可能在未来的Swift版本中支持它。

编辑:另一种说法是SomeProtocol.self.Type永远不应该是真的。我宁愿在编译时检查这个,而不是运行时检查或断言。

1 个答案:

答案 0 :(得分:1)

您可以检查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`
    }
}