使用通用协议上的代理

时间:2018-04-28 11:20:53

标签: swift generics

我有这段代码:

protocol GenericProtocol: class {
    associatedtype type
    func funca(component: type)
}

class MyType<T> {

    weak var delegate: GenericProtocol? // First error

    var t: T

    init(t: T) {
        self.t = t
    }

    func finished() {
        delegate?.funca(component: t) // Second error
    }

}

class UsingGenericProtocol: GenericProtocol {

    let myType: MyType<Int>
    typealias type = Int

    init() {
        myType = MyType<Int>(t: 0)
    }

    func funca(component: Int) {

    }

}

我想使用给定类型的委托。代码将无法编译,因为我收到了这个错误:

  

协议'GenericProtocol'只能用作通用约束   因为它有自我或相关的类型要求

  

会员'funca'不能用于协议类型的值   'GenericProtocol';使用通用约束

我可以通过从协议中删除类型,将其设置为Any然后将其转换为正确的类型来省略此错误,但我认为泛型应该涵盖此问题。有什么方法可以让这个代码编译?感谢。

2 个答案:

答案 0 :(得分:3)

泛型和相关类型之间的区别在于,在实例化时指定泛型,在实现期间指定相关类型。因此,您不能将协议类型用作具体类型,因为关联类型取决于实现类型。

但是,有一些解决方法:

1)使用委托的类型作为泛型类型:

class MyType<Delegate: GenericProtocol> {
    typealias T = Delegate.type
    ...
}

2)在委托方法中使用通用协议而不是关联类型:

protocol CommonProtocol { ... }

protocol DelegateProtocol {
    func funca(component: CommonProtocol)
}

3)使用闭包进行类型擦除(这也是在Sequence协议的AnySequence<Element>协议的Swift标准库中完成的)

struct AnyGenericProtocol<GenericType>: GenericProtocol {
    typealias type = GenericType
    private let f: (GenericType) -> ()

    init<G: GenericProtocol>(_ g: GenericProtocol) where G.type == GenericType {
        f = { component in
            g.funca(component: component)
        }
    }

    func funca(component: GenericType) {
        f(component)
    }
}

class MyType<T> {
    var delegate: AnyGenericProtocol<T>
    ...
}

答案 1 :(得分:2)

这不可能使用通用协议。请改用具体类型或通用协议。你必须在那些抽象之外声明具体的T

例如,这应该有效:

class MyType<T> {

    weak var delegate: UsingGenericProtocol<T>? // First error

    var t: T

    init(t: T) {
        self.t = t
    }

    func finished() {
        delegate?.funca(component: t) // Second error
    }

}
class UsingGenericProtocol<T>: GenericProtocol {
    let myType: MyType<T>
    typealias type = T

    init(t: T) {
        myType = MyType<T>(t: t)
    }

    func funca(component: T) {

    }
}

let instance = UsingGenericProtocol<Int>(t: 0)