[英]Downcast protocol conformance in extension
Let's say I have two non-generi c protocols (1) 假设我有两个非基因协议(1)
protocol StringValue {
var asString: String {get}
}
protocol StringProvider {
var value: StringValue {get}
}
I want to have a generic version of the second one (2) 我想拥有第二个的通用版本(2)
protocol TypedStringProvider: StringProvider { // inherits from StringProvider
associatedtype TypedStringValue: StringValue
var typedValue: TypedStringValue { get }
}
And extension with default implementation of non-generic version to have a code free conformance to StringProvider
( doesn't work , pls read below) (3) 并且使用非泛型版本的默认实现扩展,以使代码免费符合
StringProvider
( 不起作用 ,请参阅下文) (3)
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
}
Now I want several classes to conform both generic TypedStringProvider
and non-generic StringProvider
protocols (4) 现在我想要几个类来兼容泛型
TypedStringProvider
和非泛型StringProvider
协议(4)
extension UIView: TypedStringProvider {
typealias TypedStringValue = String
var typedValue: String { return "Some String" }
}
extension Double: TypedStringProvider {
typealias TypedStringValue = String
var typedValue: String { return String(self) }
}
extension String: StringValue {
var asString: String { return self }
}
And get compiler error: Type 'UIView' does not conform to protocol 'StringProvider'
. 并得到编译器错误:
Type 'UIView' does not conform to protocol 'StringProvider'
。
Seemingly extension (3) doesn't work like I want because TypedStringValue
is not a StringValue
in despite of this constraint associatedtype TypedStringValue: StringValue
from (2) 貌似扩展(3)不能像我想的那样工作,因为
TypedStringValue
不是StringValue
,尽管有这种约束associatedtype TypedStringValue: StringValue
from(2)
The question is how to conform to non-generic StringProvider
while keeping value
typed 问题是如何在保持
value
类型的同时符合非泛型StringProvider
Example : 示例 :
0.5.value.lowercased()
Of course StringValue
doesn't have lowercased
method from String
so it won't compile. 当然
StringValue
没有来自String
lowercased
方法,所以它不会编译。
What I have tried: 我尝试过的:
First is to add untyped property to extension (3) 首先是向扩展名添加无类型属性(3)
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
var value: StringValue { return typedValue }
}
Doesn't work because of Invalid redeclaration of 'value'
error 由于
Invalid redeclaration of 'value'
错误的Invalid redeclaration of 'value'
因此无法正常工作
Second is to extend my classes and add untyped property there (5) 第二是扩展我的类并在那里添加无类型属性(5)
extension UIView {
var value: StringValue { return typedValue }
}
extension Double {
var value: StringValue { return typedValue }
}
It works without compiler errors but 它工作没有编译器错误, 但
No autocompletion for lowercased
in our example. 在我们的示例中没有针对
lowercased
自动完成。
With extensions (5) I need to write a lot of code for every class conforming StringProvider
and every property this protocol has 使用扩展(5)我需要为符合
StringProvider
每个类和此协议具有的每个属性编写大量代码
Any ideas? 有任何想法吗?
value
is defined as type StringValue
, so this is the type you should specify in your extension of TypedStringProvider
in order to complete the protocol conformance: value
定义为StringValue
类型,因此这是您应在TypedStringProvider
扩展中指定的类型,以便完成协议一致性:
extension TypedStringProvider {
var value: StringValue {
return typedValue
}
}
Found solution 找到解决方案
extension StringProvider where Self: TypedStringProvider {
var value: StringValue { return typedValue }
}
With this extension there's no need to write similar extensions to every class and autocompletion works too. 使用此扩展,不需要为每个类编写类似的扩展,自动完成也可以。
Full code: 完整代码:
protocol StringValue {
var asString: String {get}
}
protocol StringProvider {
var value: StringValue {get}
}
protocol TypedStringProvider: StringProvider {
associatedtype TypedStringValue: StringValue
var typedValue: TypedStringValue { get }
}
extension StringProvider where Self: TypedStringProvider {
var value: StringValue { return typedValue }
}
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
}
extension UIView: TypedStringProvider {
typealias TypedStringValue = String
var typedValue: String { return "some string" }
}
extension Double: TypedStringProvider {
typealias TypedStringValue = String
var typedValue: String { return String(self) }
}
extension String: StringValue {
var asString: String { return self }
}
let doubleValue = 0.5.value.lowercased()
On StringProvider
you are defining value
to a StringValue
: 在
StringProvider
您要为StringValue
定义value
:
protocol StringProvider {
var value: StringValue { get }
}
but here you are defining the type to TypedStringValue
which is not the same as StringValue
. 但是在这里你要定义
TypedStringValue
的类型,它与StringValue
。 (underlying value can be TypedStringValue
, however it needs to be typecasted from StringValue
to TypedStringValue
when using it) (基础值可以是
TypedStringValue
,但是在使用它时需要从StringValue
到TypedStringValue
进行类型转换)
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
}
There are two solutions that I can come up for this scenario right now: 我现在可以为这种情况提出两种解决方案:
If you want to make value
generic and change the type based on TypedStringProvider
you can: 如果您想使
value
通用并根据TypedStringProvider
更改类型,您可以:
protocol StringProvider {
associatedtype StringProviderValue: StringValue
var value: StringProviderValue { get }
}
Conform to the protocol by defining StringProviderValue
to TypedStringValue
通过将
StringProviderValue
定义为TypedStringValue
来符合协议
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
}
Keep the StringProvider
as it is: 保持
StringProvider
原样:
protocol StringProvider {
var value: StringValue { get }
}
Conform to the protocol by using the correct StringValue
type, and inside it return typedValue: TypedStringValue
which can be downcasted to StringValue
通过使用正确的
StringValue
类型符合协议,并在其中返回typedValue: TypedStringValue
,可以下载到StringValue
extension TypedStringProvider {
var value: StringValue { return typedValue }
}
Both solutions give the same output: 两种解决方案都提供相同的输出
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.