Swift枚举可以有多个原始值吗?

问题描述 投票:17回答:9

我想将两个原始值关联到枚举实例(想象一个表示错误类型的枚举,我希望Error.Teapot具有值类型为418的Int类型属性code,以及设置为I'm a teapot的String属性。)

请注意raw valuesassociated values之间的区别 - 我希望所有Teapot实例的code为418,我不希望每个Teapot实例具有唯一的关联值。

有没有比将qazxswpo在switch上查找适当值的枚举添加计算属性更好的方法?

swift enums enumeration
9个回答
12
投票

不,枚举不能有多个原始值 - 它必须是单个值,实现self协议,并且可以像Equatable中描述的那样进行字面转换。

我认为在您的情况下最好的方法是使用错误代码作为原始值,并使用预先填充的静态字典支持的属性,错误代码为键,文本为值。


2
投票

不,您不能拥有与枚举关联的多个原始值。

在您的情况下,您可以使原始值等于代码,并具有与描述相关联的值。但我认为计算属性方法是最好的选择。


2
投票

我创造了一种模拟这种方式(与Marcos Crispino在他的回答中提出的建议没什么不同)。远非一个完美的解决方案,但允许我们为我们想要获得的每个不同的属性避免那些讨厌的开关案例。

诀窍是使用结构作为“属性/数据”持有者并在枚举本身中将其用作RawValue。

它有一些重复,但到目前为止它对我很有帮助。每次你想添加一个新的枚举案例时,编译器会提醒你在rawValue getter中填写额外的case,这应该提醒你更新documentation,它会提醒你在struct上创建新的static属性。

init?

要点代码:

Gist

1
投票

如果您想为YourError提供许多静态属性,则可以导入属性列表;您可以将根对象设置为字典,并将枚举原始值作为每个对象的键,从而可以轻松地检索对象的静态结构化数据。

这有一个导入和使用plist的例子: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

对于简单的错误描述而言,这可能是过度的,您可以使用硬编码的静态函数和您的枚举值的switch语句,返回您需要的错误字符串。只需将静态函数放在与枚举相同的.swift文件中即可。

例如,

http://www.spritekitlessons.com/parsing-a-property-list-using-swift/

这具有更好的容纳本地化的好处(与.plist解决方案相比)。但是,.plist可能只包含用于检索正确本地化的密钥,而不是用于此目的的错误字符串。


1
投票

你有几个选择。但它们都不涉及原始价值。原始值不是该任务的正确工具。

Option 1 (so-so): Associated Values

我个人强烈建议每个enum案例中有多个关联值。相关的值应该是显而易见的(因为它们没有参数/名称),并且水中有多个重度混乱。

也就是说,这是语言让你做的事情。这允许您以不同的方式定义每个案例,如果这是您需要的。例:

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

Option 2 (better): Tuples! And computed properties!

元组是Swift的一大特色,因为它们为您提供了创建特殊类型的能力。这意味着您可以在线定义它。甜!

如果你的每个错误类型都有代码和描述,那么你可以有一个计算的enum ErrorType { case teapot(String, Int) case skillet(UInt, [CGFloat]) } 属性(希望有一个更好的名字?)。见下文:

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


0
投票

这并没有特别回答你的问题,它要求找到一个比let errorCode = myErrorType.info.codeing更好的方法来通过switch来查找合适的值,但这个答案对于将来需要一种简单方法来获取字符串的人来说仍然有用。枚举,定义为整数类型。

self

这样,我们可以通过两种方式获取errorMessage:

  1. 使用整数(例如,从服务器返回的错误代码)
  2. 使用枚举值(我们为枚举定义的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!" } } }

选项1:

rawValue

选项2:

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

0
投票

在Swift的现代版本中,即使没有使用let option2 = Error.errorMessage(code: Error.Teapot.rawValue) print(option2) //prints "I'm a teapot!" rawValue声明枚举,也可以获得枚举案例标签的字符串值。

: String

因此,不再需要定义和维护一个便利功能,该功能可以打开每个案例以返回字符串文字。此外,即使没有指定原始值类型,这也适用于任何枚举。

至少,这允许您通过同时使用真正的How to get the name of enumeration value in Swift? rawValue以及用作案例标签的字符串来获得“多个原始值”。


0
投票

首先,假设您要存储代码和消息,可以使用: Int的结构

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

一些说明:

  • 您只能使用错误代码进行匹配,但如果消息不同,这可能会导致原始值不一致
  • 具有某些自定义类型的原始值所需的样板代码量可能不会产生使用关联值的好处。

0
投票

可能的解决方法是将自定义函数与枚举关联起来

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

可以用作

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

可能您可以使用其他功能将枚举类型与不同的值相关联

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