簡體   English   中英

使一個協議符合另一個協議

[英]Make a protocol conform to another protocol

我有兩個協議: PenInstrumentForProfessional 我想讓任何Pen成為InstrumentForProfessional

protocol Pen {
  var title: String {get}
  var color: UIColor {get}
}

protocol Watch {} // Also Instrument for professional
protocol Tiger {} // Not an instrument

protocol InstrumentForProfessional {
  var title: String {get}
}

class ApplePen: Pen {
  var title: String = "CodePen"
  var color: UIColor = .blue
}

extension Pen: InstrumentForProfessional {} // Unable to make ApplePen an Instument for Professional: Extension of protocol Pen cannot have an inheritance clause

let pen = ApplePen() as InstrumentForProfessional

協議可以相互繼承

協議繼承

一個協議可以繼承一個或多個其他協議,並且可以在它繼承的需求之上添加更多的需求。 協議繼承的語法類似於類繼承的語法,但可以選擇列出多個繼承的協議,用逗號分隔:

 protocol InheritingProtocol: SomeProtocol, AnotherProtocol { // protocol definition goes here }

所以,你基本上需要這樣做:

protocol InstrumentForProfessional {
    var title: String {get}
}

protocol Pen: InstrumentForProfessional {
    var title: String {get} // You can even drop this requirement, because it's already required by `InstrumentForProfessional`
    var color: UIColor {get}
}

現在,符合Pen所有內容也符合InstrumentForProfessional

以下是您如何要求符合擴展中的協議。

extension Pen where Self: InstrumentForProfessional {}

您當前的做法使編譯器認為您正在執行繼承,而不是協議一致性。

另請注意, let pen = ApplePen() as InstrumentForProfessional沒有意義並且不會編譯。

我想如果你檢查一下這個 SO 答案,它會解決同樣的問題。

https://stackoverflow.com/a/37353146/1070718

@paper1111 與您要查找的內容很接近,但我認為您確實想做:

extension InstrumentForProfessional where Self: Pen {}

由於 Pen 已經符合 InstrumentForProfessional,那么當它是 Pen 時,您只需要擴展 InstrumentForProfessional。

有時我會忘記協議繼承在 Swift 中是如何工作的,但感謝 SO 刷新了我的記憶。

已經提供了兩個答案:@user28434 為您提供了一個解決方案,前提是您可以在編寫Pen協議時添加一致性,@paper1111 為您提供了對Pen擴展獨家添加的機會類型也符合InstrumentForProfessional 注意:要利用@paper1111 的答案,您還必須將協議添加到您的類型中,如下所示:

class ApplePen: Pen, InstrumentForProfessional {
  var title: String = "CodePen"
  var color: UIColor = .blue
}

與@user28434 的答案相比,這似乎更偏離您的要求,實際上是在回答一個不同的問題(即如何向采用兩種不同協議的類型添加功能)。 因此,我會問您實際上要尋找的是否不是協議而是類繼承:

class InstrumentForProfessional {
    var title: String
    init(title:String) {
        self.title = title
    }
}

class Pen: InstrumentForProfessional {
    var color: UIColor
    init(title:String, color:UIColor) {
        self.color = color
        super.init(title: title)
    }
}

因為看起來你通過兩者中title屬性的存在得到的是類繼承常見的覆蓋行為。 所以問題就變成了為什么在使用class而不是structenum還要努力將類繼承壓縮到協議中?

如果您不想應用類繼承並且您不想在編寫Pen協議時添加繼承,並且如果您也不想向您的類添加多個協議,那么您可以做另一件事為整潔做的是使用類型別名:

protocol InstrumentForProfessional {
    var title: String {get}
}

protocol PenExtra {
    var color: UIColor {get}
    var title: String {get}
}

typealias Pen = InstrumentForProfessional & PenExtra

class ApplePen: Pen {
    var title = "CodePen"
    var color = UIColor.blue
}

但是寫完所有這些,如果您可以遵循@ user28434 的方法,那么就這樣做。

以上所有答案都解釋了如何做,但沒有解釋為什么

在考慮協議時,您必須進行心理轉換——協議不是結構。 當你定義協議一致性時,你只給出了一個一致性類型必須打包的一組必需的東西。 給予或接受該類型將如何實現它們。

protocol InstrumentForProfessional {
  var title: String {get}
}

protocol Pen: InstrumentForProfessional {
  var title: String {get}
  var color: UIColor {get}
}

protocol Watch: InstrumentForProffesional {}
protocol Tiger {} // Not an instrument

Pen 不符合InstrumentForProfessional。 InstrumentForProfessional。 另一個示例是擁有 Instrument 協議和 StringInstrument。 你知道,StringInstrument 不符合 Instrument; 一個儀器。

我認為您正在尋找的是某些字段的默認實現 考慮這個例子; 每個移動對象都應該告訴它的最大速度。 汽車是移動的物體嗎? 是的。 它應該符合MovingObject嗎? 不!

protocol MovingObject {
    /// Top speed a vehicle can reach in km/h.
    var topSpeedKMH: Double { get }
}

protocol Car: MovingObject {
    /// Horsepower of a car.
    var hp: Double { get }
    var weight: Double { get }
    
    // Note that topSpeed is also required,
    // but since we specified it in MovingObject we don't have
    // to rewrite it here.
    // var topSpeedKMH: Double { get }
}

但我們知道,我們可以根據馬力和重量計算出最高速度。 這就是我們創建默認實現的原因。

extension Car {
    var topSpeedKMH: Double {
        hp * weight
    }
}

現在每輛車都可以符合“開箱即用”的移動車輛; 然而,它仍然可以為每個給定的領域提供自己的實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM