Je veux créer un protocol
qui applique un certain cas sur tout enums
conforme à ce protocol
.
Par exemple, si j'ai un enum
comme ceci:
enum Foo{
case bar(baz: String)
case baz(bar: String)
}
Je veux l'étendre avec un protocol
qui ajoute un autre cas:
case Fuzz(Int)
Est-ce possible?
La solution consiste à utiliser un struct
avec static
variables.
Remarque: c'est ce qui se fait dans Swift pour Notification.Name
Voici une implémentation sur Swift
struct Car : RawRepresentable, Equatable, Hashable, Comparable {
typealias RawValue = String
var rawValue: String
static let Red = Car(rawValue: "Red")
static let Blue = Car(rawValue: "Blue")
//MARK: Hashable
var hashValue: Int {
return rawValue.hashValue
}
//MARK: Comparable
public static func <(lhs: Car, rhs: Car) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
protocol CoolCar {
}
extension CoolCar {
static var Yellow : Car {
return Car(rawValue: "Yellow")
}
}
extension Car : CoolCar {
}
let c1 = Car.Red
switch c1 {
case Car.Red:
print("Car is red")
case Car.Blue:
print("Car is blue")
case Car.Yellow:
print("Car is yellow")
default:
print("Car is some other color")
}
if c1 == Car.Red {
print("Equal")
}
if Car.Red > Car.Blue {
print("Red is greater than Blue")
}
Veuillez noter que cette approche ne remplace pas enum
, utilisez-la uniquement lorsque les valeurs ne sont pas connues au moment de la compilation.
non, car vous ne pouvez pas déclarer un case
en dehors d'un enum
.
Un extension
peut ajouter un enum
imbriqué, comme ceci:
enum Plants {
enum Fruit {
case banana
}
}
extension Plants {
enum Vegetables {
case potato
}
}
Voici quelques prises supplémentaires qui peuvent aider quelqu'un:
En utilisant votre exemple:
enum Foo {
case bar(baz: String)
case baz(bar: String)
}
Vous pouvez envisager de "l'imbriquer" dans un case
de votre choix enum
:
enum FooExtended {
case foo(Foo) // <-- Here will live your instances of `Foo`
case fuzz(Int)
}
Avec cette solution, il devient plus laborieux d'accéder au type associé aux cas "cachés". Mais cette simplification pourrait en fait être bénéfique dans certaines applications.
Une autre alternative passe juste par recréer et étendre tout en ayant un moyen de convertir Foo
en _ enum
FooExtended
étendu (par exemple avec un init
personnalisé):
enum FooExtended {
case bar(baz: String)
case baz(bar: String)
case fuzz(Int)
init(withFoo foo: Foo) {
switch foo {
case .bar(let baz):
self = .bar(baz: baz)
case .baz(let bar):
self = .baz(bar: bar)
}
}
}
Il peut y avoir de nombreux endroits où l'une, l'autre ou les deux solutions n'ont absolument aucun sens, mais je suis sûr qu'elles peuvent être utiles à quelqu'un là-bas (même si ce n'est que comme un exercice).