如何在方法签名中使用通用协议?

时间:2018-06-03 05:17:53

标签: swift generics protocols

上下文是我有一个类A,它有很多属性,但我只想暴露其中的一些,其中一个是泛型​​类型。

然后我尝试为A创建一个通用协议(可能是一个错误的名字?)。

看起来很好但是当我尝试在方法中使用协议而不是结构时,它不会编译。

有什么建议吗?

protocol AProtocol {
    associatedtype T

    var t: T? { get }
}

struct A<Type>: AProtocol {
    typealias T = Type
    var t: Type?

    var a: Int
    var b: Int
    var c: Int
    var d: Int
    var e: Int
}

struct Main {
    func show<T: Decodable>(a: AProtocol<T>) { // error: Cannot specialize non-generic type 'AProtocol'

    }
}

修改

下面的代码片段是在我从@ Sweeper的答案更新后,对实施进行了轻微的调整,因为最初在我的项目中它是一个闭包。

protocol AProtocol {
    associatedtype T

    var t: T? { get }
}

struct A<Type>: AProtocol {
    typealias T = Type
    var t: Type?

    var a: Int?
    var b: Int?
    var c: Int?
    var d: Int?
    var e: Int?
}

struct Main {
    func show<T, U>(completion: (U) -> Void) where T: Decodable, U: AProtocol, U.T == T {
        let a = A<Int>()
        completion(a) //error: '(A<Int>) -> Void' is not convertible to '(U) -> Void'
    }
}

你能解释为什么这不起作用吗?

1 个答案:

答案 0 :(得分:2)

您无法使用具有相关类型的协议。具有关联类型的协议与通用协议不同。后者在Swift中不存在。

在这种情况下,您通常要做的是向方法引入一个新的通用参数U并将其约束到协议:

func show<T, U>(a: U) where T: Decodable, U : AProtocol, U.T == T {

}

3个限制是:

  • T必须符合Decodable
  • U必须符合AProtocol
  • U.T必须与T
  • 相同

有道理,对吧?