2016-11-17 4 views
1

J'ai rencontré un problème conceptuel et je recherche des conseils. J'ai une classe de base qui définit toutes les propriétés communes un type d'objet donné:Limitation du protocole Swift avec avancé

class Widget { 
    var id: Int 
    var type: String 
} 

Beaucoup de ces widgets partagent d'autres propriétés et capacités qui sont facilement regroupées. Les propriétés/fonctionnalités intègrent parfaitement dans les protocoles:

protocol WidgetryA { 
    func widgetAFunc() 
} 

protocol WidgetryB { 
    func widgetBFunc() 
} 

Il est facile d'étendre la classe Widget pour se conformer à ces différents protocoles:

extension Widget: WidgetryA { 
    func widgetAFunc() { } 
} 

Notez que les widgets peuvent se conformer à de multiples protocoles. Pas de problème jusqu'à présent! Ce que je voudrais faire, et ce que je lutte avec, est la suivante ... Widgets qui ont une certaine valeur Widget.type devrait essentiellement être interdit de se conformer à un protocole Widgetry donné. Ainsi, par exemple:

// this obviously doesn't work with where -- is there an alternative? 
extension Widget: WidgetryA where Self.type == "foo" { 
    func widgetAFunc() { } 
} 

Maintenant, je pouvais faire quelque chose comme grossier et inélégant garde() uant dans les fonctions de protocole pour éviter Widgets du mal Widget.type de faire des appels qu'ils ne devraient pas. Je pense que les types associés pourraient fournir un chemin praticable pour atteindre ce que je veux, mais je me bats avec une construction qui fonctionne. Toute pensée ou conseil serait apprécié!

+0

La propriété 'type' de' Widget' est une propriété stockée (et non par exemple un type associé). Si votre exemple serait légal (sous une forme quelconque), cela signifierait que les méthodes disponibles pour un _type_ donné (qui est l'essence définit le type) seraient décidées pendant _runtime_ (basé sur la _value_ d'une propriété du type), qui n'est pas possible dans le système de frappe fort de Swifts. Une utilisation courante consiste à limiter les extensions à des types où certaines typelias (le 'associatedtype') remplit certaines conditions, mais toute cette logique est résolue pendant la compilation. – dfri

+0

Vous ne pouvez pas contraindre un protocole basé sur un attribut d'exécution. Si vous devez faire des différences typées, je recommande fortement d'utiliser des enums. – PeejWeej

Répondre

0

Ce n'est pas possible comme décrit dans Swift pour plusieurs raisons:

  1. Le compilateur Swift ne sait pas ce que les valeurs d'exécution pour la propriété « type » seront

  2. Swift les génériques et les extensions de protocole ne prennent pas en charge l'exclusion/la désactivation/la suppression des méthodes et des implémentations basées sur des contraintes, et les contraintes génériques ne prennent pas en charge les types correspondants qui ne sont PAS quelque chose.

Cependant, plutôt que d'utiliser la chaîne de type, je suggère faire le Widget « type » un protocole lui-même, puis ajoutez les mises en œuvre par extension du protocole aux instances seulement qui sont Widgets qui sont conformes au protocole de type correct (s)

+0

Les explications pour 1 et 2 ci-dessus sont super claires. Merci. Pourriez-vous élaborer un peu sur la dernière partie de votre réponse?Si j'utilise un protocole WidgetType pour Widget, je ne sais toujours pas comment structurer un protocole Widgetry, étendre le protocole WidgetType ou fournir des implémentations de protocole par défaut pour la classe Widget afin de restreindre l'utilisation d'un protocole donné. Il y a un morceau du puzzle ici que je suis toujours incapable de voir malheureusement! –

1

Vous pouvez faire une extension du protocole:

extension WidgetryA where Self: Foo { 
    func widgetAFunc() { } 
} 

donc ce widgetAFunc sera mis en œuvre que pour les classes qui sont de Foo type et conformes à WidgetryA protocole. Et bien sûr, vous devez créer des sous-classes de Widget.