[英]How to make one protocol with a property that is another protocol, yet ensure that classes which conform to the first protocol can be restricted
[英]Make a protocol conform to another protocol
我有兩個協議: Pen和InstrumentForProfessional 。 我想讓任何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
而不是struct
或enum
還要努力將類繼承壓縮到協議中?
如果您不想應用類繼承並且您不想在編寫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.