Swift - 枚举

286 阅读3分钟

在 Swift 中,枚举的作用是非常强大的,除了定义固定的离散值,它还能承载关联值、原始值、方法,甚至遵守协议,是构建类型安全 API 的关键工具之一。

什么是枚举(Enum)

枚举用于表示一组有穷且明确的值,比如状态、类型、分类等。例如 HTTP 状态码、用户角色、订单状态等。

enum UserRole {
    case admin, member, guest
}

相比用字符串或整数,枚举更加类型安全、可维护、可拓展

定义枚举的基本语法

enum DeviceType {
    case iPhone
    case iPad
    case mac
}

可以使用点语法访问枚举值:

let device: DeviceType = .iPhone

原始值

如果你想让每个枚举 case 对应一个 String 或 Int 值,可以添加原始值类型:

enum HTTPMethod: String {
    case get = "GET"
    case post = "POST"
    case put = "PUT"
}

访问:

let method = HTTPMethod.get.rawValue  // "GET"

还可以通过原始值初始化:

let method = HTTPMethod(rawValue: "POST")  // Optional(.post)

关联值

关联值允许枚举在不同 case 下携带不同类型的附加数据:

enum APIResponse {
    case success(data: Data)
    case failure(error: String)
}

使用:

let response = APIResponse.success(data: Data())

结合 switch 解包数据:

switch response {
case .success(let data):
    print("Received (data.count) bytes")
case .failure(let error):
    print("Error: (error)")
}

遍历所有枚举值

使用 CaseIterable 可以轻松访问枚举的所有 case,常用于 UI 列表:

enum Direction: String, CaseIterable {
    case north, south, east, west
}

for dir in Direction.allCases {
    print(dir.rawValue)
}

注意:**带关联值的枚举无法自动遵守 CaseIterable。

SwiftUI 中使用枚举

在 SwiftUI 中,枚举是构建 TabView 等组件的理想选择。

enum Tab: String, CaseIterable, Identifiable {
    case home, profile, settings
    var id: String { rawValue }
}

TabView {
    ForEach(Tab.allCases) { tab in
        Text("This is (tab.rawValue.capitalized)")
            .tabItem { Text(tab.rawValue.capitalized) }
    }
}

枚举与 Equatable / Hashable

不带关联值的枚举默认遵守 Equatable 和 Hashable。带关联值时:

enum Result: Equatable {
    case success(data: Int)
    case failure(code: Int)
}

Swift 会合成 ==,前提是所有关联值类型也要是 Equatable。

模式匹配

快速匹配枚举 case 而无需写完整 switch:

if case .success(let data) = response {
    print(data)
}

或用于逻辑提前退出:

guard case .success(let data) = response else {
    return
}

枚举中添加方法和计算属性

枚举不只是静态值,还可以封装行为:

enum Language {
    case swift, kotlin, dart

    var isStronglyTyped: Bool {
        switch self {
        case .swift, .kotlin: return true
        case .dart: return false
        }
    }

    func helloWorld() -> String {
        switch self {
        case .swift: return "Hello,Swift"
        case .kotlin: return "Hello,Kotlin"
        case .dart: return "Hello,Dart"
        }
    }
}

比如上面的代码,我们可以给枚举添加计算属性和函数。

使用 OptionSet 替代“多选枚举”

当你需要表示多个可组合的选项(如权限、标志)时,枚举就不太合适了,可以使用 OptionSet来实现:

struct Permission: OptionSet {
    let rawValue: Int
    static let read  = Permission(rawValue: 1 << 0)
    static let write = Permission(rawValue: 1 << 1)
    static let exec  = Permission(rawValue: 1 << 2)
}

let access: Permission = [.read, .exec]

总结

Swift 枚举远比 Objective-C 中的枚举更加强大。在 Swift 中编写代码时,枚举是一个强大的工具。它提高了代码可读性,同时可以让你享受到编译时安全性。你可以使用 CaseIterable 协议和自定义原始值创建动态代码解决方案。默认情况下,枚举是可比较的,除非你添加了关联值。