繁体   English   中英

传播中的下行协议一致性

[英]Downcast protocol conformance in extension

假设我有两个非基因协议(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和非泛型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 }
}

并得到编译器错误: Type 'UIView' does not conform to protocol 'StringProvider'

貌似扩展(3)不能像我想的那样工作,因为TypedStringValue不是StringValue ,尽管有这种约束associatedtype TypedStringValue: StringValue from(2)

问题是如何在保持value类型的同时符合非泛型StringProvider

示例

0.5.value.lowercased()

当然StringValue没有来自String lowercased方法,所以它不会编译。

我尝试过的:

首先是向扩展名添加无类型属性(3)

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

由于Invalid redeclaration of 'value'错误的Invalid redeclaration of 'value'因此无法正常工作

第二是扩展我的类并在那里添加无类型属性(5)

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

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

它工作没有编译器错误,

  1. 在我们的示例中没有针对lowercased自动完成。

  2. 使用扩展(5)我需要为符合StringProvider每个类和此协议具有的每个属性编写大量代码

有任何想法吗?

value定义为StringValue类型,因此这是您应在TypedStringProvider扩展中指定的类型,以便完成协议一致性:

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

找到解决方案

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()

问题

StringProvider您要为StringValue定义value

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 }
}

产量

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

在此输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM