iOS Swift No.8 - 枚举

第八章 枚举

枚举就是定义一组相同类型的相关值,枚举可以允许我们以类型安全的方式来处理这些值。每一组枚举它的成员的数据类型都是相同的,枚举在swift语法里面是比较灵活的,没有必要为枚举的每一个提供一个值,如果枚举的成员需要值 那么这个值可以是字符串,字符,或者整数和浮点数类型的值。

1. 枚举语法

可以用enum关键字来介绍并定义枚举,枚举名称用单数且首字母要大写

enum SomeEnumeration {
    // 这里是枚举的定义
}

下面这个例子就是指南针上的四个方向

enum CompassPoint {
    case north
    case south
    case east
    case west
}

枚举的成员可以出现在同一行,用逗号隔开每个枚举的成员。

enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
// 指南针例子的另一种写法
enum CompassPoint {
	// 枚举成员出现在同一行
    case north, south, east, west
}
// 标准表达
var directionToHead = CompassPoint.west
// 简短表达
directionToHead = .east

2. Matching Enumeration Values with a Switch statement (用Switch语句匹配枚举值)

directionToHead = .south
// 结合前面章节中的switch语句 多个case的情况
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")
}
let somePlanet = Planet.earth
// 结合switch语句 default case的情况
switch somePlanet {
case .earth:
    print("Mostly harmless")
default:
    print("Not a safe place for humans")
}

3. Iterating over enumeration cases (枚举成员的迭代)

在某些枚举中,一个很实用的方法来提供一个集合,这个集合包括枚举中的所有成员,就可以在枚举名称的后面加上CasrIterable。当然也可以用枚举类型中的allCases属性来显示这个包括所有枚举成员的集合。

enum Beverage: CaseIterable {
    case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")

输出:
3 beverages available

for循环可以用来迭代这个枚举里面的所有成员。

for beverage in Beverage.allCases {
    print(beverage)
}

输出:
coffee
tea
juice

4. Associated Values (关联值)

前面的几个例子展示了枚举成员是如何定义的,我么可以给这这个Planet.earth设置为变量或常量。并且在赋值之后才可以常看这个值。有些时候可以把存储其他类型的值和枚举成员(enumeration case)放在一起存储。这样也更加实用直观表达枚举成员和存储值之间的关系,这些给枚举成员附加的信息我们称之为关联值(assocoated values)。

例如,假设一个库存跟踪系统需要利用两种不同类型的条形码来跟踪商品。每一个条形码都是由0-9这几个数字组成的,在下面这个条形码例子中 第一位是数字系统数位(number system digit),第二位是制造商编码数位(manufacturer code digit),第三位是五位商品编码数位(product code digit),和最后一位检查数位(check digit) 来鉴别这个条形码是否被正确扫描。

UPC格式下1D条形码 ↓
在这里插入图片描述

QR编码格式线的2D条形码 这个码可以存储2953个字符的长度。在这里插入图片描述

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

上面的代码可以读作:
define an enumeration type called barcode,which can take either a value of upc with ab associated value of type(Int, Int, Int, Int) or a value of QR code with an associated value of type string。

其实上面这个例子并没有具体给出枚举成员的关联值,只是给出了这些关联值的类型 Int 和 String两种。当条形码中的存储的常量或变量值等于barcode.upc或barcode.qrCode。现在我么久可以创建一个新的条形码用关联值的类型。

var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

Line 1 : 创建新的一个叫做productBarcode并且给它一个Barcode.upc的值,这个Barcode.upc是一个是一个关联元组的值(8, 85909, 51226, 3)也就是商品的条形码。

Line 2 : 也可以重新给这个productBarcode赋一个不同的类型的条形码值。在这个时候原来的product code由Integer变成String了。

用Switch语句可以查看不同的商品的条形码。这个时候就要用到let或者var前缀来提取枚举成员里的关联值。提取常量的关联值用let前缀。变量的关联值则用var。

// 方法一
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).")
}
// 方法二
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
    print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
    print("QR code: \(productCode).")
}

5. Raw Values (原始值)

上面的关联值barcode例子像我们展示了存储不同类型的关联值在枚举成员里是如何被声明的,作为关联值的替代枚举成员可以被默认值(原始值)预填充。这些原始值的类型必须相同。原始值可以是字符,字符串,整数或浮点数类型等。但是在声明枚举的时候每一个原始值必须是唯一的。

5.1 Implicitly Assigned Raw Values ( 原始值的隐式赋值 )

当我们使用原始值类型为整数或字符床的时候,不必明确给每个枚举成员赋原始值,swift会自动帮你完成赋值的。

通常情况下整数被用作原始值,每一个枚举成员的隐含值会比前几个枚举成员要多,第一个枚举成员没有设置原始值,那么它的原始值就是0。

enum Planet: Int {
	// if first case doesn't have a value set, its value is 0
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}

所以在上面的这个例子里这个Planet.mercury有一个明确的原始值1。venus就有一个隐藏的原始值2。

enum CompassPoint: String {
	case north, south, east, west
}
let earthOrder = Planet.warth.rawValue
// 地球的顺序是3
let sunDirection = CompassPoint.west.rawValue
// 太阳升起的方向是东

上面这个是指南针的枚举例子,用String的原始值来指代方位的名称。所以呢 这个CompassPoint.west就有一个原始值west。以此类推其他的都是一样的。

5.2 Initializing from a raw value (初始化的原始值)

用原始值类型来定义枚举的时候,这个枚举就回自动获得一个初始化的方法,这个方法用来接收一个叫做rawValue作为参数。返回值要么是枚举成员中的某一个,要么就是nil。(下面会具体涉及) 可以用初始化方法来创建一个新的枚举实例。

let possiblePlanet = Planet(rawValue: 7)
/* 原始值第7个要么是枚举成员中的一个,返回该成员。要么就什么都没有,返回nil就好了。
	这符合optional type的定义。
	原始值第7个是有值的 所有这个赋值成立。 
*/
// 找到位置11上的那个原始值
let positionToFind = 11
// 用可选绑定来判断并找出这个值。(if let 关键字)
if let somePlanet = Planet(rawValue: positionToFind) {
	// 用switch语句来找出位置11上面相关联的内容
    switch somePlanet {
    // 找到的值为earth的情况
    case .earth:
        print("Mostly harmless")
    // 找到值但不是earth的情况
    default:
        print("Not a safe place for humans")
    }
    // 找不到值的情况
} else {
	// 则输出这个语句
    print("There isn't a planet at position \(positionToFind)")
}

6. Recursive Enumeration (递归枚举)

递归是什么意思呢? 中文都理解不了,差了下英文感觉和迭代,版本更新迭代有一点近似。递归枚举属于枚举的一种,把该枚举的一个实例看作为一个或多个枚举成员的关联值。用indirect关键字来表明这是一个递归枚举。枚举作地柜的时候indirect关键字会告诉,表明,要求编译器插入一个间接层。

递归:按照某一包含有限步数的法则或公式对一个或多个前面的元素进行运算,以确定一系列元素(如数或函数)的方法。

Recursive:the process of repeating a function, each time applying it to the result of the previous stage。

// 递归枚举写法1 - 在枚举成员前加indirect 表明该枚举成员可递归
enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
// 递归枚举写法2 - 在枚举introducer前加上indirect 表明该枚举的所有成员可递归。
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

案例:( 5 + 4 ) * 2 使用递归枚举

let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

line 4: 先定义了一个常量叫product,该常量会调用递归枚举(ArithmeticExpression)中的乘法运算(.multiplication),最后将参数2或复合参数sum传递进递归枚举中的乘法运算作进一步操作。

下面这函数直接将数字带入运算 方法简便明了。

func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    // 枚举成员绑定并返回该值
    case let .number(value):
        return value
    // 绑定addition中的数字成为left和right
    case let .addition(left, right):
		// 返回该绑定枚举成员left和right的值做加法运算
        return evaluate(left) + evaluate(right)
    case let .multiplication(left, right):
        return evaluate(left) * evaluate(right)
    }
}
// 输出会直接调用函数evaluate
// product: 结果,产品
print(evaluate(product))
发布了12 篇原创文章 · 获赞 71 · 访问量 1294

猜你喜欢

转载自blog.csdn.net/weixin_45026183/article/details/104958561