不支持将某些协议用作符合另一个协议的具体类型

Using some protocol as a concrete type conforming to another protocol is not supported

我正在尝试将泛型与协议混合使用,但我真的很难过 xD

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

协议A

protocol ProtocolA {

}

协议B

protocol ProtocolB : ProtocolA {

}

实现协议A

class ImplementProtocolA <P : ProtocolA> {

    let currentProtocol : P

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

}

实现协议B

class ImplementProtocolB : ImplementProtocolA<ProtocolB> {

}

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

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

1 这种“限制”有什么原因吗?

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

3 以后会支持吗?

--更新--

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

查看协议

protocol View {

}

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

演示者协议

protocol Presenter {
    typealias V : View
}

class UserDemoPresenter : Presenter {
    typealias V = GetUserView
}

错误:

UserDemoPresenter.swift Possibly intended match 'V' (aka 'GetUserView') does not conform to 'View’

那是什么??符合!

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

class UserDemoPresenter : Presenter {
    typealias V = View
}

UserDemoPresenter.swift Possibly intended match 'V' (aka 'View') does not conform to 'View'

xxDD 我真的不明白。

--更新--

使用 Rob Napier 提出的解决方案,问题并没有得到解决,相反,它只是被延迟了。

当尝试定义对 UserDemoPresenter 的引用时,我需要指定通用类型,所以我得到了同样的错误:

private var presenter : UserDemoPresenter<GetUserView>

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

限制的根本原因是 Swift 没有 first-class 元类型。最简单的例子是这不起作用:

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]。你的情况也是如此。

这是一个具体类型(好吧,它是一个抽象类型,在任何时候被实例化并且P被填充时都会变成一个具体类型):

class ImplementProtocolA<P : ProtocolA>

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

class ImplementProtocolB : ImplementProtocolA<ProtocolB>

你需要把它具体化。这将编译:

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

还有:

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

只是因为您以后可能会 运行 解决这个问题:如果您制作这些结构或 final classes,您的生活会变得容易得多。混合协议、泛型和 class 多态性充满了非常尖锐的边缘。有时你很幸运,它就是不会编译。有时它会调用你意想不到的东西。

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


private var presenter : UserDemoPresenter<GetUserView>

这仍然是一个抽象类型。你是说:

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

如果这会产生问题,您需要创建一个框。请参阅 以了解有关如何进行类型擦除以保留抽象类型的讨论。但是你需要在具体类型中工作。您最终无法专注于协议。在大多数情况下,您最终必须专注于具体的事情。