web-dev-qa-db-ja.com

プロトコルを使用して既存の列挙型にケースを追加する

このprotocolに準拠するすべてのenumsに特定のケースを強制するprotocolを作成したいと思います。

たとえば、次のようなenumがあるとします。

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

別のケースを追加するprotocolで拡張したい:

case Fuzz(Int)

これは可能ですか?

19
cfischer

設計

回避策は、struct変数とともにstaticを使用することです。

注:これはSwift for Notification.Name

以下は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")
}

注意:

このアプローチはenumの代替ではないことに注意してください。これは、コンパイル時に値が不明な場合にのみ使用してください。

35
user1046037

いいえ、caseの外でenumを宣言することはできないためです。

8
R Menke

extensionは、次のようにネストされたenumを追加できます。

enum Plants {
  enum Fruit {
     case banana
  }
} 


extension Plants {
  enum Vegetables {
     case potato
  }
}
6
Mark

ここに誰かが役立つかもしれないいくつかの追加のテイクがあります:

あなたの例を使用して:

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

あなた自身のcaseenumにそれを「ネスト」することを考えることができます:

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

このソリューションでは、「非表示」のケースに関連付けられたタイプにアクセスするのがさらに面倒になります。しかし、この単純化は、特定のアプリケーションでは実際に有益な場合があります。

もう1つの方法は、Fooを拡張enumFooExtendedに変換する方法を用意しながら、それを再作成して拡張することです(たとえば、カスタム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)
        }
    }
}

これらのソリューションのどちらか、または両方がまったく意味をなさないところがたくさんあるかもしれませんが、私はそれらがそこにいる誰かにとって便利であると確信しています(たとえ演習としても)。

2
fbeeper