不支持将某些协议用作符合另一个协议的具体类型
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>
}
如果这会产生问题,您需要创建一个框。请参阅 以了解有关如何进行类型擦除以保留抽象类型的讨论。但是你需要在具体类型中工作。您最终无法专注于协议。在大多数情况下,您最终必须专注于具体的事情。
我正在尝试将泛型与协议混合使用,但我真的很难过 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>
}
如果这会产生问题,您需要创建一个框。请参阅