Swift 中的枚举 — 是什么、语法和使用

作者: IT Sectr 发布日期: 2026-06-17 阅读时间: 6 分钟

枚举在 Swift 中是一种将一组相关值统一在一个名称下的类型。与 C 和 Objective-C 不同,其中枚举仅仅是整数常量的集合,Swift 提供了第一类枚举,具有关联值、原始值、方法和协议支持。根据 Apple, 2026,枚举是 iOS 开发中类型安全状态建模的关键工具之一。

要点

  • 枚举 — 用于一组相关值的类型,确保类型安全
  • 原始值 — 枚举所有 case 的相同类型的相同值
  • 关联值 — 不同的数据类型,单独附加到每个 case
  • Case 使用关键字 case 声明,可以包含方法
  • Switch 与枚举需要编译器穷尽所有变体

Swift 中的枚举是什么?

枚举是一种用户定义的数据类型,它组合了一组有限的互斥变体。在 Swift 中,枚举不仅仅是数字常量,而是一个拥有自身逻辑的完整类型。

枚举的每个变体称为 case。与 Objective-C 不同,其中枚举被简化为整数类型,Swift 允许每个 case 存储自己的数据并拥有方法。

根据 Apple,Swift 中的枚举支持泛型、初始化器、计算属性和协议实现 — 这使得它适用于状态、错误、选项和有限状态机的建模。

在任何需要表示有限集合的互斥变体时使用枚举:屏幕状态、错误类型、方向、筛选选项。

声明枚举的语法

枚举使用关键字 enum 后跟名称和花括号中的主体来声明。

swift
enum CompassDirection {
    case north
    case south
    case east
    case west
}

Case 可以用逗号在一行中声明:

swift
enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

要访问 case,在已知类型后使用点语法

swift
let direction = CompassDirection.north
// 已知类型 — 可使用简写语法:
var currentPlanet = .earth

在将变量赋值给已知的枚举类型后,Swift 会自动推断类型,访问 case 时可以省略枚举名称。

枚举中的原始值

原始值是分配给枚举每个 case 的相同类型的值。与关联值不同,原始值对所有 case 类型相同,并在声明时设置。

swift
enum HTTPStatusCode: Int {
    case ok = 200
    case notFound = 404
    case internalServerError = 500
}

let code = HTTPStatusCode.notFound
print(code.rawValue) // 404

对于整数原始值,如果只显式指定了第一个,Swift 会自动递增值:

swift
enum Status: Int {
    case pending = 1
    case active      // 2
    case completed   // 3
}

原始值可以是 IntStringCharacter 或任何符合 RawRepresentable 协议的类型。Swift 会自动生成初始化器 init? 以从原始值创建枚举 — 这在解析 API 数据时非常方便。

枚举中的关联值

关联值允许将不同的数据类型单独附加到枚举的每个 case。与原始值不同,关联值可以在类型和数量上有所不同。

swift
enum NetworkError {
    case timeout(seconds: Int)
    case httpError(code: Int, message: String)
    case noConnection
    case unknown(error: Error)
}

通过 switch 处理时,关联值通过绑定到变量或常量来提取:

swift
let error = NetworkError.httpError(code: 403, message: "Forbidden")

switch error {
case .timeout(let seconds):
    print("\(seconds)s 后超时")
case .httpError(let code, let message):
    print("HTTP \(code): \(message)")
case .noConnection:
    print("无连接")
case .unknown(let err):
    print("未知:\(err.localizedDescription)")
}

根据 Apple 文档,关联值使枚举成为建模复杂状态的表达性工具,无需创建单独的包装类型。将它们用于类似 Result 的场景和带有上下文的错误建模。

递归枚举 (indirect)

递归枚举 — 其 case 引用枚举类型本身的枚举。这样的 case 用关键字 indirect 标记。

swift
indirect enum LinkedList<T> {
    case empty
    case node(value: T, next: LinkedList<T>)
}

关键字 indirectenum 之前将所有 case 标记为递归。或者,可以仅用 indirect 标记特定 case:

swift
enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}

Swift 使用 indirect 将递归 case 存储为引用(引用语义)而不是值 — 这避免了枚举在栈上的无限大小。递归枚举广泛用于构建树、链表和 AST。

枚举与协议

枚举可以像结构体和类一样实现协议。这是 Swift 中面向协议编程的关键能力。

swift
protocol Describable {
    var description: String { get }
}

enum PaymentMethod: Describable {
    case creditCard(last4: String)
    case applePay
    case bankTransfer

    var description: String {
        switch self {
        case .creditCard(let last4):
            return "Card ending in \(last4)"
        case .applePay:
            return "Apple Pay"
        case .bankTransfer:
            return "Bank Transfer"
        }
    }
}

枚举还可以实现 Cocoa 协议 — 例如,CaseIterable 用于自动生成所有 case 的集合,或 Codable 用于序列化。这使得枚举成为 Swift 应用程序中的通用构建块。

常见问题

Swift 中枚举和结构体有什么区别?

枚举是具有有限互斥变体集的类型,而结构体是具有任意属性集的类型。枚举不能有存储属性,但支持计算属性和方法。

枚举可以同时拥有原始值和关联值吗?

不可以,枚举不能同时拥有原始值和关联值。原始值是所有 case 的相同类型的值,关联值是每个 case 的单独数据。这些机制是互斥的。

如何获取枚举所有 case 的数组?

添加对 CaseIterable 协议的遵守。Swift 会自动生成属性 allCases,它按声明顺序返回所有 case 的集合。这便于遍历所有变体。

是否必须使用 switch 来处理枚举?

Switch 是最安全的方法,因为编译器会检查穷尽覆盖。可以使用 if case 检查单个 case,或对没有关联值的枚举使用 ==

可以创建带有泛型的枚举吗?

是的,枚举支持泛型:enum Result<T, E> { case success(T); case failure(E) }。这允许创建类型安全的通用结构来处理成功和错误。

总结

  • 枚举在 Swift 中 — 具有方法、泛型和协议支持的完整类型
  • 原始值允许为所有 case 设置相同类型的相同值
  • 关联值提供了将不同数据附加到每个 case 的能力
  • Indirect case 对于枚举中的递归结构是必需的
  • 协议可以由枚举实现 — 这是 Swift 中 POP 的基础
  • Switch 与枚举保证了编译级别的穷尽处理
  • 使用枚举建模有限状态和类型安全选项

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读