简介
在 Swift 中,enum(枚举)是值类型,用于定义一组相关值,并且可以为这些值赋予关联值、原始值,甚至添加方法和计算属性。相比于 C 语言中的简单枚举,Swift 的枚举功能更强大,接近“代数数据类型”。
基本语法
定义枚举
关键字enum、case
enum Direction {
case north
case south
case east
case west
}
简写
enum Direction {
case north, south, east, west
}
如:
enum RequestType{
case get
case post
}
配合switch case使用
let dir = Direction.north
switch dir {
case .north:
print("Going North")
case .south:
print("Going South")
default:
print("Going Somewhere")
}
switch 在 Swift 中必须穷尽所有情况,否则必须加
default
关联值(Associated Values)
可以为枚举成员携带额外信息。
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var code = Barcode.upc(8, 85909, 51226, 3)
switch code {
case .upc(let a, let b, let c, let d):
print("UPC: \(a)-\(b)-\(c)-\(d)") // 取其中携带的 额外信息
case .qrCode(let str):
print("QR Code: \(str)")
}
原始值(Raw Values)
为每个成员赋固定的值(只能是 String、Int、Double 等字面量)
(原始值不写的话默认是枚举值)
enum Grade: String {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
print(Grade.perfect) // 枚举值:perfect
print(Grade.perfect.rawValue) // 原始值:A
- 如果枚举的原始值类型是
Int、String,Swift会自动分配原始值
enum Season: Int {
case spring, summer, autumn, winter
}
print(Season.spring.rawValue) // 0
print(Season.summer.rawValue) // 1
print(Season.autumn.rawValue) // 2
print(Season.winter.rawValue) // 3
添加方法和计算属性
enum Direction {
case north, south, east, west
func isVertical() -> Bool {
return self == .north || self == .south
}
var description: String {
switch self {
case .north: return "↑"
case .south: return "↓"
case .east: return "→"
case .west: return "←"
}
}
CaseIterable
令枚举遵循 CaseIterable 协议。Swift 会为其生成一个 allCases 属性,表示一个包含枚举所有成员的集合。下面是一个例子:
enum Beverage: CaseIterable {
case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
for beverage in Beverage.allCases {
print(beverage)
}
Equatable / Comparable
Swift 默认对没有关联值的 enum 自动实现 Equatable。你可以手动实现 Comparable
enum Rank: Int, Comparable {
case two = 2, three, four, five, six
static func < (lhs: Rank, rhs: Rank) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
嵌套枚举
struct Chess {
enum Piece {
case king, queen, bishop
}
}
let piece = Chess.Piece.king
带泛型的枚举
Swift 标准库中大量使用泛型枚举
enum Result<Success, Failure: Error> {
case success(Success)
case failure(Failure)
}
与 Codable 搭配使用
当使用关联值时,实现 Codable 需要自定义 init(from:) 和 encode(to:)
enum ServerResponse: Codable {
case success(message: String)
case failure(code: Int)
enum CodingKeys: String, CodingKey {
case type, message, code
}
enum ResponseType: String, Codable {
case success, failure
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(ResponseType.self, forKey: .type)
switch type {
case .success:
let message = try container.decode(String.self, forKey: .message)
self = .success(message: message)
case .failure:
let code = try container.decode(Int.self, forKey: .code)
self = .failure(code: code)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .success(let message):
try container.encode(ResponseType.success, forKey: .type)
try container.encode(message, forKey: .message)
case .failure(let code):
try container.encode(ResponseType.failure, forKey: .type)
try container.encode(code, forKey: .code)
}
}
}
递归枚举
枚举值包含自己枚举,需要使用关键字indirect
indirect enum ArithExpr {
case number(Int)
case sum(ArithExpr, ArithExpr)
case difference(ArithExpr, ArithExpr)
}
let five = ArithExpr.number(5)
let four = ArithExpr.number(4)
let two = ArithExpr.number(2)
let sum = ArithExpr.sum(five, four)
let difference = ArithExpr.difference(sum, two)
可以使用MemoryLayout获取数据类型占用的内存大小
enum Password {
case number(Int, Int, Int, Int)
case other
}
MemoryLayout<Password>.stride // 40, 分配占用的空间大小
MemoryLayout<Password>.size // 33, 实际用到的空间大小
MemoryLayout<Password>.alignment // 8, 对齐参数