Adding a case to an existing enum with a protocol

前端 未结 4 1292
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-15 04:40

I want to create a protocol that enforces a certain case on all enums conforming to this protocol.

For example, if I have a <

相关标签:
4条回答
  • 2020-12-15 05:19

    no, since you can't declare a case outside of an enum.

    0 讨论(0)
  • 2020-12-15 05:20

    Design

    The work around is to use a struct with static variables.

    Note: This is what is done in Swift 3 for Notification.Name

    Below is an implementation on Swift 3

    Struct:

    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

    protocol CoolCar {
    
    }
    
    extension CoolCar {
    
        static var Yellow : Car {
    
            return Car(rawValue: "Yellow")
        }
    }
    
    extension Car : CoolCar {
    
    }
    

    Invoking

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

    Note:

    Please note this approach is not a substitute for enum, use this only when the values are not known at compile time.

    0 讨论(0)
  • 2020-12-15 05:25

    An extension can add a nested enum, like so:

    enum Plants {
      enum Fruit {
         case banana
      }
    } 
    
    
    extension Plants {
      enum Vegetables {
         case potato
      }
    }
    
    0 讨论(0)
  • 2020-12-15 05:42

    Here are a couple additional takes that may help somebody out there:

    Using your example:

    enum Foo {
        case bar(baz: String)
        case baz(bar: String)
    } 
    

    You can consider to "nest" it in a case of your own enum:

    enum FooExtended {
        case foo(Foo) // <-- Here will live your instances of `Foo`
        case fuzz(Int)
    }
    

    With this solution, it becomes more laborious to access the "hidden" cases associated type. But this simplification could actually be beneficial in certain applications.

    Another alternative passes by just recreate and extend it while having a way to convert Foo into the extended enum FooExtended (eg. with a custom init):

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

    There may be many places where one, the other, or both of these solutions make absolutely no sense, but I'm pretty sure they may be handy to somebody out there (even if only as an exercise).

    0 讨论(0)
提交回复
热议问题