web-dev-qa-db-fra.com

Rendre un protocole conforme à un autre protocole

J'ai deux protocoles: Pen et InstrumentForProfessional. Je voudrais faire de tout Pen un 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
13
Richard Topchii

Voici comment vous exigez la conformité aux protocoles dans les extensions.

extension Pen where Self: InstrumentForProfessional {}

La façon dont vous procédez actuellement fait penser au compilateur que vous faites l'héritage, pas la conformité au protocole.

Notez également que let pen = ApplePen() as InstrumentForProfessional n'a pas de sens et ne compile pas.

7
paper1111

Les protocoles peuvent hériter les uns des autres :

Héritage de protocole

Un protocole peut hériter d'un ou plusieurs autres protocoles et peut ajouter d'autres exigences en plus des exigences dont il hérite. La syntaxe de l'héritage de protocole est similaire à la syntaxe de l'héritage de classe, mais avec l'option de répertorier plusieurs protocoles hérités, séparés par des virgules:

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

Donc, vous devez essentiellement faire ceci:

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

Maintenant, tout ce qui est conforme à Pen est également conforme à InstrumentForProfessional.

4
user28434

Deux réponses ont déjà été fournies: @ user28434 vous fournit une solution sous l'hypothèse que vous pouvez ajouter la conformité au moment où vous écrivez le protocole Pen et @ paper1111 vous offre la possibilité de faire des ajouts à l'extension Pen exclusive à l'endroit où le type est également conforme à InstrumentForProfessional. Remarque: pour profiter de la réponse de @ paper1111, vous devez également ajouter le protocole à votre type comme ceci:

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

Ce qui semble s'éloigner davantage de vos besoins que la réponse de @ user28434, et répond en fait à une question différente (comment ajouter des fonctionnalités à un type qui adopte deux protocoles différents). Par conséquent, je demanderais si ce que vous recherchez n'est pas un protocole mais un héritage de classe:

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

Parce qu'il semble que ce que vous obtenez à travers l'existence de la propriété title dans les deux est le comportement prioritaire commun à l'héritage de classe. La question devient donc pourquoi lutter pour compresser l'héritage de classe dans un protocole lorsque vous utilisez class plutôt que struct ou enum de toute façon?

Si vous ne voulez pas appliquer l'héritage de classe et que vous ne voulez pas ajouter d'héritage au moment d'écrire le protocole Pen, et si vous ne voulez pas non plus ajouter plusieurs protocoles à votre classe, alors une autre chose que vous pourriez faire pour la netteté est d'utiliser une typealias:

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
}

Mais après avoir écrit tout cela, si vous pouvez suivre l'approche de @ user28434, faites-le.

2
sketchyTech