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

时间:2014-12-30 14:01:56

标签: swift enums enumeration

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

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

是否有更好的方法是将计算属性添加到switch self上的{{1}}以查找相应值的枚举?

10 个答案:

答案 0 :(得分:11)

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

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

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

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

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

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

Gist

要点代码:

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 :(得分:1)

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

这是一个导入和使用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可能只包含用于检索正确本地化而不是错误字符串的密钥。

答案 4 :(得分:1)

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

选项1(马马虎虎):相关值

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

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

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

答案 5 :(得分:0)

这并不是特别回答您的问题,而是要求找到一种比switch 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!"
        }
    }
}

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

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

答案 6 :(得分:0)

在现代版本的Swift中,可以获取枚举大小写标签的字符串值,甚至可以使用: String rawValue声明 without 枚举。

How to get the name of enumeration value in Swift?

  

因此,不再需要定义和维护一个便捷函数,该函数在每种情况下都将打开以返回字符串文字。此外,即使未指定原始值类型,此方法也可以自动用于任何枚举。

这至少可以让您拥有真实的: Int rawValue以及用作案例标签的字符串,从而获得“多个原始值”。

答案 7 :(得分:0)

首先,假设您要存储代码和消息,可以将结构用于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
    }
}

一些注意事项:

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

答案 8 :(得分: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())")
 }

输出

Case: 0
View: 1
Information: 2

可能您可以具有其他功能来将枚举类型关联到不同的值

答案 9 :(得分: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
        }
    }
}