假设我有两个非泛型 c协议(1)
protocol StringValue {
var asString: String {get}
}
protocol StringProvider {
var value: StringValue {get}
}
我想要第二个(2)
的通用版本protocol TypedStringProvider: StringProvider { // inherits from StringProvider
associatedtype TypedStringValue: StringValue
var typedValue: TypedStringValue { get }
}
具有默认实现的非通用版本的扩展,使其与StringProvider
完全无代码兼容(不起作用,请参见下文)(3)
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
}
现在,我希望几个类同时符合 和通用TypedStringProvider
协议(4) >
StringProvider
并得到编译器错误: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 }
}
。
貌似扩展名(3)不能像我想要的那样工作,因为尽管Type 'UIView' does not conform to protocol 'StringProvider'
受(2)的约束,TypedStringValue
并不是StringValue
问题是如何在保持associatedtype TypedStringValue: StringValue
键入的同时遵守非通用StringProvider
示例:
value
当然,0.5.value.lowercased()
没有StringValue
中的lowercased
方法,因此不会编译。
我尝试过的事情:
首先是将未类型化的属性添加到扩展名(3)
String
由于extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
var value: StringValue { return typedValue }
}
错误而无法正常工作
第二是要扩展我的课程,并在其中添加未键入的属性(5)
Invalid redeclaration of 'value'
它有效,没有编译器错误,但但是
在我们的示例中,extension UIView {
var value: StringValue { return typedValue }
}
extension Double {
var value: StringValue { return typedValue }
}
没有自动完成。
具有扩展名(5),我需要为每个符合lowercased
的类和该协议具有的每个属性编写很多代码
有什么想法吗?
答案 0 :(得分:0)
value
被定义为类型StringValue
,因此,您应该在扩展名TypedStringProvider
中指定此类型,以完成协议一致性:
extension TypedStringProvider {
var value: StringValue {
return typedValue
}
}
答案 1 :(得分:0)
找到解决方案
extension StringProvider where Self: TypedStringProvider {
var value: StringValue { return typedValue }
}
有了这个扩展,就不必为每个类编写类似的扩展,自动补全也可以工作。
完整代码:
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()
答案 2 :(得分:0)
在StringProvider
上,您将value
定义为StringValue
:
protocol StringProvider {
var value: StringValue { get }
}
,但是在这里您将类型定义为TypedStringValue
,与StringValue
不同。 (基础值可以为TypedStringValue
,但使用时需要从StringValue
到TypedStringValue
进行类型转换)
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
}
对于这种情况,我现在可以提出两种解决方案:
如果要使value
为通用名称,并根据TypedStringProvider
更改类型,可以:
protocol StringProvider {
associatedtype StringProviderValue: StringValue
var value: StringProviderValue { get }
}
通过将StringProviderValue
定义为TypedStringValue
来符合协议
extension TypedStringProvider {
var value: TypedStringValue { return typedValue }
}
保持StringProvider
不变:
protocol StringProvider {
var value: StringValue { get }
}
通过使用正确的StringValue
类型符合协议,并在其中返回typedValue: TypedStringValue
,可以将其向下转换为StringValue
extension TypedStringProvider {
var value: StringValue { return typedValue }
}
两个解决方案都提供相同的输出: