简体   繁体   English

传播中的下行协议一致性

[英]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 它工作没有编译器错误,

  1. No autocompletion for lowercased in our example. 在我们的示例中没有针对lowercased自动完成。

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

Problem 问题

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

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

Solution

There are two solutions that I can come up for this scenario right now: 我现在可以为这种情况提出两种解决方案:

1. Generic Approach 1.通用方法

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

2. StringValue approach 2. StringValue方法

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

Output 产量

Both solutions give the same output: 两种解决方案都提供相同的输出

在此输入图像描述

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

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