枚举为一组相关值定义了一个公共类型,使您能够在代码中以类型安全的方式处理这些值。
如果您熟悉C
,您将知道C
枚举将相关名称分配给一组整数值。 Swift
中的枚举更加灵活,并且不必为枚举的每个案例提供值。 如果为每个枚举情况提供了一个值(称为“原始”值),则该值可以是字符串,字符或任何整数或浮点类型的值。
在Swift
中,枚举是一等类型,可以提供一些在其他语言中类对象才有的特性。
-
枚举语法 (Enumeration Syntax)
使用enum
关键字引入枚举,并将其整个定义放在一对大括号中:
enum SomeEnumeration {
// enumeration definition goes here
}
以下是指南针的四个要点的示例:
enum CompassPoint {
case north
case south
case east
case west
}
case
关键字明确了要定义的枚举成员值(相当于定义变量时使用的var
关键字,定义枚举成员值则使用关键字case
)。与C
语言不同的是,这些变量并没有被定义成0,1,2,3
这些整型值。
多个成员值可以在同一行,用逗号隔开。
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
每个枚举定义都定义了一个新类型。 与Swift
中的其他类型一样,它们的名称(例如CompassPoint
和Planet
)应该以大写字母开头。 给出枚举类型单数而不是复数名称,以便它们看起来不言自明:
var directionToHead = CompassPoint.west
此时我们已经知道directionToHead
是一个CompassPoint
类型了,如果需要改变值,可以省略CompassPoint
directionToHead = .east
-
使用Switch语句匹配枚举值 (Matching Enumeration Values with a Switch Statement)
directionToHead = .south
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("Watch out for penguins")
case .east:
print("Where the sun rises")
case .west:
print("Where the skies are blue")
}
// Prints "Watch out for penguins"
如控制流程中所述,在考虑枚举的情况时,switch
语句必须是详尽的。 如果省略.west
的情况,则此代码不会编译,因为它不考虑CompassPoint
案例的完整列表。 要求详尽无遗确保枚举案例不会被意外遗漏。
如果不适合为每个枚举提供案例,可以提供一个默认案例:
let somePlanet = Planet.earth
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
// Prints "Mostly harmless"
-
遍历枚举用例 (Iterating over Enumeration Cases)
对于某些枚举,拥有所有枚举的案例集合很有用。 您可以通过在枚举名称后写入:CaseIterable
来启用此功能。 Swift
将所有案例的集合公开为枚举类型的allCases
属性。 这是一个例子:
enum Beverage: CaseIterable {
case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases().count
print("\(numberOfChoices) beverages available")
// Prints "3 beverages available"
遍历枚举
for beverage in Beverage.allCases() {
print(beverage)
}
// coffee
// tea
// juice
-
关联值 (Associated Values)
枚举成员值可以不关联同一种类型的值,也就是说,枚举中的每个成员都可以设置不同的关联值。
举个例子,定义一个条码枚举,里面有二维码和条形码两种类型,这两种类型关联的值不同,可以这样定义。
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
使用如下:
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
也可以使用switch的值绑定
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
// Prints "QR code: ABCDEFGHIJKLMNOP."
如果枚举案例的所有关联值都被提取为常量,或者如果所有关联值都被提取为变量,则可以在案例名称前放置单个var
或let
注释,以简洁起见:
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
print("QR code: \(productCode).")
}
// Prints "QR code: ABCDEFGHIJKLMNOP."
-
原始值 (Raw Values)
“关联值”中的条形码示例显示了枚举的情况如何声明它们存储了不同类型的关联值。 作为关联值的替代,枚举情况可以预先填充默认值(称为原始值),它们都是相同的类型。
enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
1.隐式分配原始值 (Implicitly Assigned Raw Values)
当你在操作存储整数或字符串原始值枚举的时候,你不必显式地给每一个成员都分配一个原始值。当你没有分配时,Swift
将会自动为你分配值。
实际上,当整数值被用于作为原始值时,每成员的隐式值都比前一个大一。如果第一个成员没有值,那么它的值是0
。
下面的枚举是先前的Planet
枚举的简化,用整数原始值来代表从太阳到每一个行星的顺序
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
隐式指定string
原始值
enum CompassPoint: String {
case north, south, east, west
}
您可以使用其rawValue属性访问枚举大小写的原始值:
let earthsOrder = Planet.earth.rawValue
// earthsOrder is 3
let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"
2.使用原始值初始化 (Initializing from a Raw Value)
如果你用原始值类型来定义一个枚举,那么枚举就会自动收到一个可以接受原始值类型的值的初始化器(叫做 rawValue
的形式参数)然后返回一个枚举成员或者 nil
。你可以使用这个初始化器来尝试创建一个枚举的新实例。
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet is of type Planet? and equals Planet.uranus
如果您尝试查找位置为11的行星,则原始值初始值设定项返回的可选行星值将为零:
let positionToFind = 11
if let somePlanet = Planet(rawValue: positionToFind) {
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
} else {
print("There isn't a planet at position \(positionToFind)")
}
// Prints "There isn't a planet at position 11"
-
递归枚举 (Recursive Enumerations)
递归枚举是枚举,它将枚举的另一个实例作为一个或多个枚举个案的关联值。 您通过在其之前写入indirect
来指示枚举情况是递归的,这告诉编译器插入必要的间接层。
例如,这是一个存储简单算术表达式的枚举:
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
也可以把indirect
写在外面,自动判断成员变量在需要递归的时候递归
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
这个枚举可以表示三种数学运算:单纯的数,加法运算,乘法运算
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
递归枚举的使用
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product))
// Prints "18"
网友评论