您有几个选择,但都不包括原始值。原始值并不是完成此任务的正确工具。
我个人强烈建议每个枚举情况最多只有一个关联值。关联值应该非常明显(因为它们没有参数/名称),而且拥有多个关联值会使事情变得混乱不清。
尽管如此,这是语言能够让您做的事情。如果需要的话,这允许您不同地定义每个情况。例如:
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
Equatable
协议,并且可以像文档描述的那样进行文字转换。文档。init?
,这将提醒您在结构体上创建新的静态属性。
Gist
代码见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
如果您希望为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"
}
}
不,枚举类型不能有多个原始值。
在您的情况下,您可以将原始值设置为代码,并使用描述关联值。但是我认为在这里使用计算属性方法是最佳选项。
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
首先,假设您想存储代码和消息,您可以使用一个结构体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
}
}
一些注意事项:
self
进行 switch
查找适当值更好的方法,但这个答案对于未来需要以整数类型定义为枚举的字符串的简单获取方式仍然有用。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!"
}
}
}
这样,我们可以通过两种方式获取错误消息:
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!"
首先,枚举应该只有一个原始值。但是如果你想要有一些可以使用多个原始值的东西... 有一种“黑客”方法可以实现这一点,但你必须自己实现可编码和可哈希化,实现自定义的初始化等。
enum MyCustomEnum: Codable, Hashable {
// duplicate every case with associated value of Codable.Type
case myFirstCase, _myFirstCase(Codable.Type)
case mySecondCase, _mySecondCase(Codable.Type)
case myThirdCase, _myThirdCase(Codable.Type)
case unknown(Any), _unknown(Codable.Type, Any) // handles unknown values
// define an allCases value to determine the only values your app 'sees'.
static var allCases: [Self] {
return [
.myFirstCase,
.mySecondCase,
.myThirdCase
// unknown(String) // you can add unknown as well, but this is too mask any unknown values.
]
}
static func == (lhs: MyCustomEnum, rhs: MyCustomEnum) -> Bool {
return lhs.stringValue == rhs.stringValue // can be either one of your custom raw values.
}
// add this per raw value. In this case one for Int and one for String
init(rawValue: Int) {
guard let value = Self.allCases.first(where:{ $0.intValue == rawValue }) else {
self = ._unknown(Int.self, rawValue)
return
}
switch value {
case .myFirstCase: self = ._myFirstCase(Int.self)
case .mySecondCase: self = ._mySecondCase(Int.self)
case .myThirdCase: self = ._myThirdCase(Int.self)
default: self = ._unknown(Int.self, rawValue)
}
}
init(rawValue: String) {
guard let value = Self.allCases.first(where:{ $0.stringValue == rawValue }) else {
self = ._unknown(String.self, rawValue)
return
}
switch value {
case .myFirstCase: self = ._myFirstCase(String.self)
case .mySecondCase: self = ._mySecondCase(String.self)
case .myThirdCase: self = ._myThirdCase(String.self)
default: self = ._unknown(Int.self, rawValue)
}
}
// add this per raw value. In this case one for Int and one for String
var intValue: Int {
switch self {
case .myFirstCase, ._myFirstCase(_): return 1
case .mySecondCase, ._mySecondCase(_): return 2
case .myThirdCase, ._myThirdCase(_): return 3
case .unknown(let value), ._unknown(_, let value): return value as? Int ?? -1 // you can also choose to let intValue return optional Int.
}
}
var stringValue: String {
switch self {
case .myFirstCase, ._myFirstCase(_): return "my first case"
case .mySecondCase, ._mySecondCase(_): return "my second case"
case .myThirdCase, ._myThirdCase(_): return "my third case"
case .unknown(let value), ._unknown(_, let value): return value as? String ?? "not a String" // you can also choose to let stringValue return optional String.
}
}
// determine the codable type using Mirror
private func getCodableType() -> Codable.Type? {
let mirrorOfModuleType = Mirror.init(reflecting: self)
guard let childOfModuleType = mirrorOfModuleType.children.first else { // no children, means no associated values.
return nil
}
let value = childOfModuleType.value // can be either Codable.Type, String or (Codable.Type & String)
if let rawValue = value as? Codable.Type {
return rawValue
} else {
guard let rawValue = value as? (Codable.Type, String) else {
// unknown(String), we don't know the rawValue as given, but try in this part of the code to guess what type fits best.
if self.stringValue != "\(self.intValue)" { // e.g. "1" might match 1 but "1.0" and 1 don't match
return String.self
} else {
return Int.self // return either a default value, or nil. It's your choice.
}
}
return rawValue.0
}
}
// confine to hashable using getCodableType
func hash(into hasher: inout Hasher) {
if self.getCodableType() is String.Type {
hasher.combine(self.stringValue)
} else { // if you don't call hasher.combine at all, you can expect strange issues. If you do not know the type, choose one that is most common.
hasher.combine(self.intValue)
}
}
// confine to Decodable
init(from decoder: Decoder) throws {
if let rawValue = try? Int.init(from: decoder) {
self.init(rawValue: rawValue)
} else if let rawValue = try? String.init(from: decoder) {
self.init(rawValue: rawValue)
} else {
throw DecodingError.valueNotFound(Self.self, DecodingError.Context(codingPath: [], debugDescription: "no matching value was found"))
}
}
// confine to Encodable using getCodableType
func encode(to encoder: Encoder) throws {
let rawValue = self.getCodableType()
if rawValue is String.Type {
try self.stringValue.encode(to: encoder)
} else if rawValue is Int.Type {
try self.intValue.encode(to: encoder)
} else {
// getCodableType returns nil if it does not know what value it is. (e.g. myFirstCase without associated value) If you want to support this as well, you can encode using one of your rawValues to the encoder.
throw EncodingError.invalidValue(Self.self, EncodingError.Context.init(codingPath: [], debugDescription: "this enum does not have a correct value", underlyingError: nil))
}
}
}
只要它们是可编码的,这段代码就可以扩展到任意数量的原始值
: String
rawValue声明枚举,也可以获取枚举案例标签的字符串值。
如何在Swift中获取枚举值的名称?
至少这样可以通过同时拥有真正的因此,不再需要定义和维护一个方便函数来切换每个案例以返回字符串文字。此外,这适用于任何枚举,即使未指定原始值类型。
: Int
rawValue和用作案例标签的字符串来实现“多个原始值”。