web-dev-qa-db-ja.com

Swift enumは複数の生の値を持つことができますか?

Enumインスタンスに2つの生の値を関連付けたい(エラータイプを表すenumを想像してください。_Error.Teapot_に、値418のIntタイププロパティcodeと、_I'm a teapot_。)

生の値関連する値 の違いに注意してください-すべてのTeapotインスタンスにcode of 418、Teapotインスタンスごとに一意の関連付けられた値が必要ない。

switchselfedした列挙型に計算されたプロパティを追加して適切な値を検索するよりも良い方法はありますか?

20
Robert Atkins

いいえ、列挙は複数の生の値を持つことはできません-Equatableプロトコルを実装する単一の値である必要があり、 documentation で説明されているようにリテラル変換可能である必要があります。

あなたのケースでの最良のアプローチは、エラーコードを生の値として使用し、エラーコードをキーとして、テキストを値として、事前入力された静的ディクショナリに裏打ちされたプロパティを使用することです。

15
Antonio

私はこれをシミュレートする方法を作成しました(Marcos Crispinoが彼の答えで提案したものと同じです)。完璧なソリューションとは言えませんが、取得したいすべての異なるプロパティについて、厄介なスイッチケースを回避できます。

秘訣は、構造体を「プロパティ/データ」ホルダーとして使用し、それを列挙型自体のRawValueとして使用することです。

少し重複していますが、今のところうまくいきます。新しい列挙型ケースを追加するたびに、コンパイラはrawValueゲッターに追加のケースを入力するように通知します。これにより、init?を更新して、新しい静的プロパティを作成するように通知する必要があります。構造体。

要旨

要旨のコード:

enum VehicleType : RawRepresentable {

    struct Vehicle : Equatable {
        let name: String
        let wheels: Int

        static func ==(l: Vehicle, r: Vehicle) -> Bool {
            return l.name == r.name && l.wheels == r.wheels
        }

        static var bike: Vehicle {
            return Vehicle(name: "Bicycle", wheels: 2)
        }

        static var car: Vehicle {
            return Vehicle(name: "Automobile", wheels: 4)
        }

        static var bus: Vehicle {
            return Vehicle(name: "Autobus", wheels: 8)
        }
    }

    typealias RawValue = Vehicle

    case car
    case bus
    case bike

    var rawValue: RawValue {
        switch self {
        case .car:
            return Vehicle.car
        case .bike:
            return Vehicle.bike
        case .bus:
            return Vehicle.bus
        }
    }

    init?(rawValue: RawValue) {
        switch rawValue {
        case Vehicle.bike:
            self = .bike
        case Vehicle.car:
            self = .car
        case Vehicle.bus:
            self = .bus
        default: return nil
        }
    }
}

VehicleType.bike.rawValue.name
VehicleType.bike.rawValue.wheels
VehicleType.car.rawValue.wheels

VehicleType(rawValue: .bike)?.rawValue.name => "Bicycle"
VehicleType(rawValue: .bike)?.rawValue.wheels => 2
VehicleType(rawValue: .car)?.rawValue.name => "Automobile"
VehicleType(rawValue: .car)?.rawValue.wheels => 4
VehicleType(rawValue: .bus)?.rawValue.name => "Autobus"
VehicleType(rawValue: .bus)?.rawValue.wheels => 8
3
Nuno Gonçalves

いくつかのオプションがあります。しかし、どちらも生の値を含みません。生の値は、タスクに適したツールではありません。

オプション1(so-so):関連する値

私は個人的に、列挙型のケースごとに複数の関連する値が存在しないようにすることを強くお勧めします。関連する値は非常に明白である必要があり(引数/名前がないため)、複数の値を設定すると、水が著しく濁ります。

そうは言っても、それはその言語でできることです。これにより、必要に応じて、各ケースを別々に定義することもできます。例:

enum ErrorType {
    case teapot(String, Int)
    case skillet(UInt, [CGFloat])
}

オプション2(より良い):タプル!そして計算された特性!

タプルはアドホックタイプを作成する機能を提供するため、Swiftの優れた機能です。つまり、インラインで定義できることを意味します。

エラータイプごとにコードと説明がある場合は、計算されたinfoプロパティを使用できます(うまくいけば、より適切な名前を付けますか?)。下記参照:

enum ErrorType {
    case teapot
    case skillet

    var info: (code: Int, description: String) {
        switch self {
        case .teapot:
            return (418, "Hear me shout!")
        case .skillet:
            return (326, "I'm big and heavy.")
        }
    }
}

おいしいドット構文を使用できるため、これを呼び出すとはるかに簡単になります。

let errorCode = myErrorType.info.code

2
jakehawken

いいえ、列挙型に複数の生の値を関連付けることはできません。

あなたのケースでは、コードと等しい生の値を持ち、説明と関連付けられた値を持つことができます。しかし、ここでは計算されたプロパティのアプローチが最良のオプションだと思います。

2
Marcos Crispino

YourErrorに多くの静的プロパティが必要な場合の回避策の1つは、プロパティリストをインポートすることです。ルートオブジェクトをディクショナリに設定し、enumのraw値を各オブジェクトのキーとして使用すると、オブジェクトの静的構造化データを簡単に取得できます。

これは、plistのインポートと使用の例です: http://www.spritekitlessons.com/parsing-a-property-list-using-Swift/

これは、単にエラーの説明としてはやり過ぎかもしれません。ハードコードされた静的関数を列挙値のswitchステートメントで使用して、必要なエラー文字列を返すことができます。列挙型と同じ.Swiftファイルに静的関数を配置するだけです。

例えば、

static func codeForError(error : YourErrorType) -> Int {
    switch(error) {
        case .Teapot:
            return "I'm a Teapot"
        case .Teacup:
            return "I'm a Teacup"
        ...
        default:
            return "Unknown Teaware Error"
    }
}

これには、(。plistソリューションと比較して)より適切なローカリゼーションの利点があります。ただし、.plistには、この目的のために、エラー文字列ではなく、適切なローカリゼーションを取得するために使用されるキーのみを含めることができます。

1
DivideByZer0

はじめに、コードとメッセージを保存する場合、RawValueの構造体を使用できます

struct ErrorInfo {
    let code: Int
    let message: String
}

次のステップでは、列挙型をRawRepresentableとして定義し、ErrorInfoを未加工の値として使用します。

enum MyError: RawRepresentable {
    typealias RawValue = ErrorInfo

    case teapot

残っているのは、MyErrorErrorInfoのインスタンス間をマッピングすることです。

static private let mappings: [(ErrorInfo, MyError)] = [
        (ErrorInfo(code: 418, message: "I'm a teapot"), .teapot)
    ]

上記で、列挙型の完全な定義を構築しましょう:

enum MyError: RawRepresentable {
    static private let mappings: [(ErrorInfo, MyError)] = [
    (ErrorInfo(code: 418, message: "I'm a teapot"), .teapot)
    ]

    case teapot

    init?(rawValue: ErrorInfo) {
        guard let match = MyError.mappings.first(where: { $0.0.code == rawValue.code && $0.0.message == rawValue.message}) else {
            return nil
        }
        self = match.1
    }

    var rawValue: ErrorInfo {
        return MyError.mappings.first(where: { $0.1 == self })!.0
    }
}

いくつかのメモ:

  • 照合にはエラーコードのみを使用できますが、メッセージが異なる場合、生の値に一貫性がなくなる可能性があります
  • 一部のカスタムタイプの未加工の値を取得するために必要なボイラープレートコードの量によっては、関連する値を使用するメリットが得られない場合があります。
1
Cristik

Swiftの最新バージョンでは、列挙型ケースラベルの文字列値を取得できますなしその列挙型が_: String_ rawValueで宣言されています)。

Swiftで列挙値の名前を取得する方法

そのため、文字列リテラルを返すためにケースごとに切り替える便利な関数を定義して維持する必要がなくなりました。さらに、生の値のタイプが指定されていない場合でも、これはどの列挙型でも自動的に機能します。

これにより、少なくとも、実際の_: Int_ rawValueとケースラベルとして使用される文字列の両方を使用して、「複数の未加工値」を取得できます。

0
pkamb

可能な回避策は、カスタム関数を列挙型に関連付けることです。

 enum ToolbarType : String{
        case Case = "Case", View="View", Information="Information"
        static let allValues = [Case, View, Information]

        func ordinal() -> Int{
            return ToolbarType.allValues.index(of: self)!
        }
 }

として使用できます

 for item in ToolbarType.allValues {
        print("\(item.rawValue): \(item.ordinal())")
 }

出力

Case: 0
View: 1
Information: 2

おそらく、列挙型を異なる値に関連付ける追加の関数を使用できます

0

私はそれをただトリッキーだと思います、そして私は以下のように私自身のアイデアを作成しました:

enum Gender:NSNumber
{
    case male = 1
    case female = 0

    init?(strValue: String?) {
        switch strValue {
        case Message.male.value:
            self = .male
        case Message.female.value:
            self = .female
        default: return nil
        }
    }

    var strValue: String {
        switch self {
        case .male:
            return Message.male.value
        case .female:
            return Message.female.value
        }
    }
}

これは、適切な値を検索するためにswitchingからselfまでより良い方法を見つけることを求めていた質問に特に答えることはありませんが、この答えは、将来的に探している人にとってまだ役立つかもしれません整数型として定義されている列挙型から文字列を取得する簡単な方法が必要です。

enum Error: UInt {
    case Teapot = 418
    case Kettle = 419

    static func errorMessage(code: UInt) -> String {
        guard let error = Error(rawValue: code) else {
            return "Unknown Error Code"
        }

        switch error {
        case .Teapot:
            return "I'm a teapot!"
        case .Kettle:
            return "I'm a kettle!"
        }
    }
}

このようにして、2つの方法でerrorMessageを取得できます。

  1. 整数(例:サーバーからエラーコードとして返されたもの)
  2. 列挙型の値(列挙型に対して定義するrawValue

オプション1:

let option1 = Error.errorMessage(code: 418)
print(option1)  //prints "I'm a teapot!"

オプション2:

let option2 = Error.errorMessage(code: Error.Teapot.rawValue)
print(option2)  //prints "I'm a teapot!"    
0
vastopa