简体   繁体   English

使一个协议符合另一个协议

[英]Make a protocol conform to another protocol

I have two protocols: Pen and InstrumentForProfessional .我有两个协议: PenInstrumentForProfessional I'd like to make any Pen to be an 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

Protocols can inherit each other : 协议可以相互继承

Protocol Inheritance协议继承

A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits.一个协议可以继承一个或多个其他协议,并且可以在它继承的需求之上添加更多的需求。 The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas:协议继承的语法类似于类继承的语法,但可以选择列出多个继承的协议,用逗号分隔:

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

So, you basically need to do this:所以,你基本上需要这样做:

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

Now everything that conforms to Pen conforms to InstrumentForProfessional too.现在,符合Pen所有内容也符合InstrumentForProfessional

Here is how you require conformance to protocols in extensions.以下是您如何要求符合扩展中的协议。

extension Pen where Self: InstrumentForProfessional {}

The current way that you are doing makes the compiler think that you are doing inheritance, not protocol conformance.您当前的做法使编译器认为您正在执行继承,而不是协议一致性。

Also note that let pen = ApplePen() as InstrumentForProfessional doesn't make sense and won't compile.另请注意, let pen = ApplePen() as InstrumentForProfessional没有意义并且不会编译。

I think if you check over at this SO answer, it solves the same problem.我想如果你检查一下这个 SO 答案,它会解决同样的问题。

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

@paper1111 was close to what you're looking for, but I think you really want to do : @paper1111 与您要查找的内容很接近,但我认为您确实想做:

extension InstrumentForProfessional where Self: Pen {}

Since Pen already conforms to InstrumentForProfessional then you just need to extend InstrumentForProfessional when it is a Pen.由于 Pen 已经符合 InstrumentForProfessional,那么当它是 Pen 时,您只需要扩展 InstrumentForProfessional。

Sometimes I forget how protocol inheritance works in Swift but thanks to SO for refreshing my memory.有时我会忘记协议继承在 Swift 中是如何工作的,但感谢 SO 刷新了我的记忆。

Two answers have already been provided: @user28434 is providing you with a solution under the assumption that you can add the conformance at the time that you write the Pen protocol and @paper1111 is providing you with the opportunity to make additions to the Pen extension exclusive to where the type also conforms to InstrumentForProfessional .已经提供了两个答案:@user28434 为您提供了一个解决方案,前提是您可以在编写Pen协议时添加一致性,@paper1111 为您提供了对Pen扩展独家添加的机会类型也符合InstrumentForProfessional Note: to take advantage of @paper1111's answer you must also add the protocol to your type like so:注意:要利用@paper1111 的答案,您还必须将协议添加到您的类型中,如下所示:

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

Which seems to stray further from your requirements than the answer from @user28434, and in fact is answering a different question (which is how to add functionality to a type that adopts two different protocols).与@user28434 的答案相比,这似乎更偏离您的要求,实际上是在回答一个不同的问题(即如何向采用两种不同协议的类型添加功能)。 Therefore I would ask whether what you are actually looking for is not protocol but class inheritance:因此,我会问您实际上要寻找的是否不是协议而是类继承:

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

Because it seems that what you are getting at through the existence of the title property in both is the overriding behaviour common to class inheritance.因为看起来你通过两者中title属性的存在得到的是类继承常见的覆盖行为。 So the question becomes why wrestle to squeeze class inheritance into a protocol when you are using class rather than struct or enum anyway?所以问题就变成了为什么在使用class而不是structenum还要努力将类继承压缩到协议中?

If you don't want to apply class inheritance and you don't want to add inheritance at the time of writing the Pen protocol, and if you also don't want to add multiple protocols to your class, then one other thing you could do for neatness is to use a typealias:如果您不想应用类继承并且您不想在编写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
}

But having written all this, if you can follow @user28434's approach then do so.但是写完所有这些,如果您可以遵循@ user28434 的方法,那么就这样做。

All the above answers explain how to do it, but not why .以上所有答案都解释了如何做,但没有解释为什么

When thinking about protocols, you have to make a mental switch - protocols are not structures.在考虑协议时,您必须进行心理转换——协议不是结构。 When you define protocol conformance, you only give a set of required things that a conforming type has to pack.当你定义协议一致性时,你只给出了一个一致性类型必须打包的一组必需的东西。 Give or take how that type is going to implement them.给予或接受该类型将如何实现它们。

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

A Pen doesn't conform to InstrumentForProfessional. Pen 不符合InstrumentForProfessional。 It is InstrumentForProfessional.InstrumentForProfessional。 Another example would be having Instrument protocol and having a StringInstrument.另一个示例是拥有 Instrument 协议和 StringInstrument。 You know, StringInstrument doesn't conform to Instrument;你知道,StringInstrument 不符合 Instrument; it is an Instrument.一个仪器。

What I think you are looking for is default implementations of certain fields.我认为您正在寻找的是某些字段的默认实现 Consider this example;考虑这个例子; every MovingObject should tell its maximum speed.每个移动对象都应该告诉它的最大速度。 Is Car a moving object?汽车是移动的物体吗? Yes, it is.是的。 Should it conform to MovingObject?它应该符合MovingObject吗? NO!不!

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

But we know that we can calculate top speed from horsepower and weight.但我们知道,我们可以根据马力和重量计算出最高速度。 That's why we create a default implementation.这就是我们创建默认实现的原因。

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

Every Car now can conform to a MovingVehicle "out-of-the-box";现在每辆车都可以符合“开箱即用”的移动车辆; yet, it could still provide its own implementation for every given field.然而,它仍然可以为每个给定的领域提供自己的实现。

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

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