扩展协议中的下行协议一致性

时间:2019-03-21 12:37:35

标签: ios swift

假设我有两个非泛型 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'

它有效,没有编译器错误,但但是

  1. 在我们的示例中,extension UIView { var value: StringValue { return typedValue } } extension Double { var value: StringValue { return typedValue } } 没有自动完成。

  2. 具有扩展名(5),我需要为每个符合lowercased的类和该协议具有的每个属性编写很多代码

有什么想法吗?

3 个答案:

答案 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,但使用时需要从StringValueTypedStringValue进行类型转换)

extension TypedStringProvider { 
    var value: TypedStringValue { return typedValue }
}

解决方案

对于这种情况,我现在可以提出两种解决方案:

1。通用方法

如果要使value为通用名称,并根据TypedStringProvider更改类型,可以:

protocol StringProvider {
    associatedtype StringProviderValue: StringValue
    var value: StringProviderValue { get }
}

通过将StringProviderValue定义为TypedStringValue来符合协议

extension TypedStringProvider {
    var value: TypedStringValue { return typedValue }
}

2。 StringValue方法

保持StringProvider不变:

protocol StringProvider {
    var value: StringValue { get }
}

通过使用正确的StringValue类型符合协议,并在其中返回typedValue: TypedStringValue,可以将其向下转换为StringValue

extension TypedStringProvider {
    var value: StringValue { return typedValue }
}

输出

两个解决方案都提供相同的输出:

enter image description here

相关问题