首页 文章

不支持使用某些协议作为符合其他协议的具体类型

提问于
浏览
54

我正在尝试将泛型与协议混合在一起,我的xD非常困难

我在Android / Java项目中实现了某些架构,我正在尝试重写它以适应swift / iOS项目 . 但我发现了这个限制 .

ProtocolA

protocol ProtocolA {

}

ProtocolB

protocol ProtocolB : ProtocolA {

}

ImplementProtocolA

class ImplementProtocolA <P : ProtocolA> {

    let currentProtocol : P

    init(currentProtocol : P) {
        self.currentProtocol = currentProtocol
    }

}

ImplementProtocolB

class ImplementProtocolB : ImplementProtocolA<ProtocolB> {

}

因此,当我尝试将ProtocolB设置为实现ProtocolA的具体类型时,我收到此错误:

Using 'ProtocolB' as a concrete type conforming to protocol 'ProtocolA' is not supported

1这种“限制”有什么理由吗?

2是否有任何解决方法可以实现此功能?

3它会在某个时候得到支持吗?

--UPDATED--

我认为同一问题的另一个变种是:

View protocols

protocol View {

}

protocol GetUserView : View {
    func showProgress()
    func hideProgress()
    func showError(message:String)
    func showUser(userDemo:UserDemo)
}

Presenter protocols

protocol Presenter {
    typealias V : View
}

class UserDemoPresenter : Presenter {
    typealias V = GetUserView
}

Error:

UserDemoPresenter.swift可能意图匹配'V'(又名'GetUserView')不符合'View'

那是什么??它符合!

即使我使用View而不是GetUserView,它也不会编译 .

class UserDemoPresenter : Presenter {
    typealias V = View
}

UserDemoPresenter.swift可能意图匹配'V'(又名'View')不符合'View'

xxDD我真的不明白 .

--UPDATED--

根据Rob Napier提出的解决方案,问题并没有解决,相反,它只是延迟了 .

当尝试定义对UserDemoPresenter的引用时,我需要指定泛型类型,因此我得到相同的错误:

private var presenter : UserDemoPresenter<GetUserView>

不支持使用'GetUserView'作为符合协议'GetUserView'的具体类型

1 回答

  • 54

    限制的根本原因是Swift没有一流的元类型 . 最简单的例子是这不起作用:

    func isEmpty(xs: Array) -> Bool {
        return xs.count == 0
    }
    

    从理论上讲,这段代码可以工作,如果确实如此,我可以制作很多其他类型(如Functor和Monad,今天真的无法在Swift中表达) . 但你不能 . 你需要帮助Swift将它钉到具体类型 . 通常我们使用泛型来做到这一点:

    func isEmpty<T>(xs: [T]) -> Bool {
        return xs.count == 0
    }
    

    请注意, T 在这里完全是多余的 . 我没有理由表达它;它从未使用过 . 但是Swift需要它,所以它可以将抽象的 Array 变成具体的 [T] . 在你的情况下也是如此 .

    这是一个具体的类型(好吧,它实例化了's an abstract type that will be turned into a concrete type any time it'并填充了 P ):

    class ImplementProtocolA<P : ProtocolA>
    

    这是一个完全抽象的类型,Swift没有任何规则可以变成具体类型:

    class ImplementProtocolB : ImplementProtocolA<ProtocolB>
    

    你需要使它具体化 . 这将编译:

    class ImplementProtocolB<T: ProtocolB> : ImplementProtocolA<T> {}
    

    并且:

    class UserDemoPresenter<T: GetUserView> : Presenter {
        typealias V = T
    }
    

    只是因为你're likely to run into the issue later: your life will go much easier if you' ll会产生这些结构或 final 类 . 混合协议,泛型和类多态性充满了非常尖锐的边缘 . 有时你're lucky and it just won' t编译 . 有时它会调用你不期望的东西 .

    您可能对A Little Respect for AnySequence感兴趣,其中详细介绍了一些相关问题 .


    private var presenter : UserDemoPresenter<GetUserView>
    

    这仍然是一种抽象类型 . 你的意思是:

    final class Something<T: GetUserView> {
        private var presenter: UserDemoPresenter<T>
    }
    

    如果这会产生问题,则需要创建一个框 . 有关如何键入擦除的讨论,请参阅Protocol doesn't conform to itself?,以便您可以保存抽象类型 . 但是你需要在具体类型中工作 . 你最终不能专注于协议 . 在大多数情况下,你最终必须专注于具体的事情 .

相关问题