【问题标题】:Adding a case to an existing enum with a protocol使用协议向现有枚举添加案例
【发布时间】:2015-12-01 16:52:56
【问题描述】:

我想创建一个protocol,它对所有符合protocolenums 强制执行特定大小写。

例如,如果我有这样的enum

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

我想用 protocol 扩展它,添加另一个案例:

case Fuzz(Int)

这可能吗?

【问题讨论】:

    标签: swift enums protocols


    【解决方案1】:

    设计

    解决方法是使用structstatic 变量。

    注意:这是在 Swift 3 中为 Notification.Name

    所做的

    以下是 Swift 3

    上的实现

    结构:

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

    注意:

    请注意,此方法不能替代 enum,仅在编译时未知值时使用此方法。

    【讨论】:

    • 为什么要把protocol CoolCar留空,只是为了扩展它...?
    • 这只是为了表明它是可以扩展的,而且这个解决方案甚至可以使用扩展。 CoolCar 可能在框架中定义(例如:标准库/基金会),您可能无法直接修改它。你可以扩展它,这个解决方案仍然有效
    • 我们如何从这个结构中创建像 Car.Red(parameter: String) 这样的案例?
    • 问题是现在您需要始终为 switch 定义默认值。
    • 该开关不适用于 uitableview。如果我这样做并且我需要在 cellforrow 中切换以检查它是哪个部分,它将无法正常工作
    【解决方案2】:

    不,因为您不能在 enum 之外声明 case

    【讨论】:

      【解决方案3】:

      extension 可以添加嵌套的enum,如下所示:

      enum Plants {
        enum Fruit {
           case banana
        }
      } 
      
      
      extension Plants {
        enum Vegetables {
           case potato
        }
      }
      

      【讨论】:

        【解决方案4】:

        这里有几个额外的镜头可能会对那里的人有所帮助:

        使用您的示例:

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

        您可以考虑将其“嵌套”在您自己的case 中的enum

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

        使用此解决方案,访问“隐藏”案例关联类型变得更加费力。但这种简化实际上在某些应用中可能是有益的。

        另一种方法是通过重新创建和扩展它,同时将Foo 转换为扩展的enum FooExtended(例如,使用自定义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)
                }
            }
        }
        

        在很多地方,这些解决方案中的一个、另一个或两个都完全没有意义,但我很确定它们对那里的人来说可能很方便(即使只是作为练习)。

        【讨论】:

          猜你喜欢
          • 2016-05-09
          • 2016-04-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-22
          • 1970-01-01
          • 2013-01-15
          • 1970-01-01
          相关资源
          最近更新 更多