Enumインスタンスに2つの生の値を関連付けたい(エラータイプを表すenumを想像してください。_Error.Teapot
_に、値418のIntタイププロパティcode
と、_I'm a teapot
_。)
生の値 と 関連する値 の違いに注意してください-すべてのTeapot
インスタンスにcode
of 418、Teapot
インスタンスごとに一意の関連付けられた値が必要ない。
switch
でself
edした列挙型に計算されたプロパティを追加して適切な値を検索するよりも良い方法はありますか?
いいえ、列挙は複数の生の値を持つことはできません-Equatable
プロトコルを実装する単一の値である必要があり、 documentation で説明されているようにリテラル変換可能である必要があります。
あなたのケースでの最良のアプローチは、エラーコードを生の値として使用し、エラーコードをキーとして、テキストを値として、事前入力された静的ディクショナリに裏打ちされたプロパティを使用することです。
私はこれをシミュレートする方法を作成しました(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
いくつかのオプションがあります。しかし、どちらも生の値を含みません。生の値は、タスクに適したツールではありません。
私は個人的に、列挙型のケースごとに複数の関連する値が存在しないようにすることを強くお勧めします。関連する値は非常に明白である必要があり(引数/名前がないため)、複数の値を設定すると、水が著しく濁ります。
そうは言っても、それはその言語でできることです。これにより、必要に応じて、各ケースを別々に定義することもできます。例:
enum ErrorType {
case teapot(String, Int)
case skillet(UInt, [CGFloat])
}
タプルはアドホックタイプを作成する機能を提供するため、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
いいえ、列挙型に複数の生の値を関連付けることはできません。
あなたのケースでは、コードと等しい生の値を持ち、説明と関連付けられた値を持つことができます。しかし、ここでは計算されたプロパティのアプローチが最良のオプションだと思います。
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には、この目的のために、エラー文字列ではなく、適切なローカリゼーションを取得するために使用されるキーのみを含めることができます。
はじめに、コードとメッセージを保存する場合、RawValue
の構造体を使用できます
struct ErrorInfo {
let code: Int
let message: String
}
次のステップでは、列挙型をRawRepresentable
として定義し、ErrorInfo
を未加工の値として使用します。
enum MyError: RawRepresentable {
typealias RawValue = ErrorInfo
case teapot
残っているのは、MyError
とErrorInfo
のインスタンス間をマッピングすることです。
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
}
}
いくつかのメモ:
Swiftの最新バージョンでは、列挙型ケースラベルの文字列値を取得できますなしその列挙型が_: String
_ rawValueで宣言されています)。
そのため、文字列リテラルを返すためにケースごとに切り替える便利な関数を定義して維持する必要がなくなりました。さらに、生の値のタイプが指定されていない場合でも、これはどの列挙型でも自動的に機能します。
これにより、少なくとも、実際の_: Int
_ rawValueとケースラベルとして使用される文字列の両方を使用して、「複数の未加工値」を取得できます。
可能な回避策は、カスタム関数を列挙型に関連付けることです。
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
おそらく、列挙型を異なる値に関連付ける追加の関数を使用できます
私はそれをただトリッキーだと思います、そして私は以下のように私自身のアイデアを作成しました:
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
}
}
}
これは、適切な値を検索するためにswitch
ingから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を取得できます。
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!"