使用协议向现有枚举添加案例

问题描述 投票:0回答:5

我想创建一个

protocol
,对所有符合此
enums
protocol
强制执行某种情况。

例如,如果我有一个像这样的

enum

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

我想用

protocol
来扩展它,添加另一种情况:

case Fuzz(Int)

这可能吗?

swift enums protocols
5个回答
46
投票

设计

解决方法是使用

struct
static
变量。

注意:这是 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
,仅当编译时未知值时才使用此方法。


13
投票

不可以,因为您不能在

case
之外声明
enum


7
投票

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

enum Plants {
  enum Fruit {
     case banana
  }
} 


extension Plants {
  enum Vegetables {
     case potato
  }
}

3
投票

这里有一些额外的建议可能会对其他人有所帮助:

用你的例子:

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

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


0
投票
的存在

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

在采用此协议的所有枚举中,我选择强制存在一个静态函数,该静态函数“生成”此情况下有效的内容,并接受此情况作为载体的 Int。因此:

case fuzz(Int) 要在特定枚举中采用和实现这一点,我会写,例如:

protocol HasIntCarryingCase {
    static func carryInt(int: Int) -> Self
}

这样,在调用站点,一段代码想要

make
 这种情况并用它的 Int 填充它,它会简单地调用 
enum Foo: HasIntCarryingCase { case bar(bar: String) case baz(baz: String) case fuzz(fuzz: Int) static func carryInt(int: Int) -> Self { .fuzz(fuzz: int) } }

,将要携带的 Int 交给它。此调用可以在任何需要 Foo 实例的地方使用,就像实际情况一样: carryInt

在我的特定用法中,无需在与实际案例名称无关的情况下向枚举询问所携带的 Int,因为所需案例的名称在调用站点是已知的。但很明显,如果您需要的话,您可以制作另一个 

let myIntCarrying: Foo = .carryInt(int: 42)
(不是 
func

,而是正常的)从这个特殊的 Int 携带案例中提取 Int。

    

© www.soinside.com 2019 - 2024. All rights reserved.