簡體   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