级别: ★☆☆☆☆
标签:「iOS」「Swift 5.1」「枚举」「迭代枚举」「枚举关联值」「递归枚举」
做者: 沐灵洛
审校: QiShare团队php
一个枚举类型是为一组相关联的值定义的一个公共类型,使得这些关联值可以在代码中以类型安全的方式进行处理。 C语言中的枚举类型将相关的枚举项使用整数值表示。而Swift中的枚举更灵活,而且没有为枚举项提供值。若是为为枚举项提供值(则该值称为原始值raw value
),该值能够是字符串,字符,任何整数或浮点类型的值。 另外,枚举项能够指定任何类型的关联值与枚举项的值一块儿存储。咱们能够定义一组通用的相关项做为枚举的一部分,每一个枚举都有一组比较合适的类型的不一样值与之关联。同时Swift中的枚举类型采用了许多只有类才支持的特征,好比枚举:git
使用enum关键字引入枚举,并将其整个定义放在{}
中github
enum <#name#> {
case <#case#>
}
复制代码
枚举的定义与使用express
enum CompassPoint {
case north
case west
case east
case south
}
//多个枚举写在一行中。
enum CompassPoint {
case north,west,east,south
}
复制代码
每一个枚举定义都定义了一个新类型。编程
var direction : CompassPoint = .north
var direction = CompassPoint.north
复制代码
let direction : CompassPoint = .north
switch direction {
case .east:
print("ease")
case .north:
print("north")
case .west:
print("west")
case .south:
print("south")
}
复制代码
经过在枚举名称后使用: CaseIterable
,可使枚举,拥有一个关于全部枚举项的集合。调用枚举类型的allCases
属性,能够获取这个集合。swift
enum CompassPoint : CaseIterable{
case north,west,east,south
}
//输出allCases
/*
log:[swift_basic.EnumerationPractice.CompassPoint.north, swift_basic.EnumerationPractice.CompassPoint.west, swift_basic.EnumerationPractice.CompassPoint.east, swift_basic.EnumerationPractice.CompassPoint.south]
*/
print(CompassPoint.allCases)
switch CompassPoint.allCases.first! {
case .north:
print("输出正确")
default:
print("输出失败")
}
//eachCase每一项都是枚举类型的示例
for eachCase in CompassPoint.allCases {
/*north
west
east
south*/
print(eachCase)
}
复制代码
枚举类型中在枚举项的旁边存贮额外的其余类型的值,这些值被称为关联值。而且每次在代码中使用有关联值的枚举项时,该关联值都会有所不一样。 Swift中能够定义枚举以存储任何给定类型的关联值,而且每一个枚举项的值类型也能够不一样。 例如:商品码有二维码和条形码两种形式。二维码的信息能够提取为String
类型,条形码的信息是一串数字,按照:一位系统数字+五位制造商标识+五位产品标识+一位校验数字的格式,咱们能够联想到(Int,Int,Int,Int)
元组类型。因此咱们使用关联值定义枚举类型以下: 通用商品条码安全
enum ProductCode {
case upc(Int,Int,Int,Int)//通用商品条码
case qrCode(String)//二维码
}
复制代码
上述代码解读:定义了一个枚举类型ProductCode
,有两个枚举项upc
和qrCode
。这两个枚举项分别能够存储(Int, Int, Int, Int)
类型和String
类型的关联值。 ProductCode
枚举类型的定义不提供任何实际意义的Int
或String
值。 它只定义ProductCode
常量和变量在等于ProductCode.upc
或ProductCode.qrCode
时能够存储的关联值的类型。bash
var productCode = ProductCode.upc(1, 22, 333, 4444)
productCode = ProductCode.qrCode("二维码哈")
复制代码
使用Switch
语句匹配枚举项而且提取枚举项的关联值。可使用let
和var
将每一个关联值提取为常量或变量,以在case
的正文中使用。微信
var productCode = ProductCode.upc(1, 22, 333, 4444)
switch productCode {
case .upc(let x, let y, let z, let zz):
print("从switch语句中提取的相匹配的枚举项的关联值为x:\(x) y:\(y) z:\(z) zz:\(zz)")
case ProductCode.qrCode(let str):
print("从switch语句中提取的相匹配的枚举项的关联值为:\(str)")
}
productCode = ProductCode.qrCode("二维码哈")
switch productCode {
case let .upc(x, y, z, zz):
print("从switch语句中提取的相匹配的枚举项的关联值为x:\(x) y:\(y) z:\(z) zz:\(zz)")
case let .qrCode(str):
print("从switch语句中提取的相匹配的枚举项的关联值为:\(str)")
}
复制代码
关联值的示例中展现了枚举如何声明它们存储不一样类型的关联值。做为关联值的替代,枚举也能够预先填充默认值(称为原始值),它们都是相同的类型。闭包
enum NameType : String{
case ZhangFei = "张飞"
case GuanYu = "关羽"
case LiuBei = "刘备"
}
let name = NameType.ZhangFei
print(name.rawValue)//!< log:张飞
复制代码
枚举NameType
的原始值被定义为String
类型,并被设置原始值。原始值能够是字符串,字符或任何整数或浮点数类型。每一个原始值在其枚举声明中必须是惟一的。
原始值与关联值不一样。原始值:预先填充的默认值,对于特定的枚举项,其原始值老是相同的。关联值:每次基于枚举状况之一建立一个常量或变量时,其关联值能够是不一样的。
隐式分配原始值
使用原始值为整数或字符串类型的枚举时,能够不用为每一个case
显式分配原始值。由于Swift会自动为咱们分配值。例如,当整数用于原始值时,每种状况的隐含值比前一种状况多一个。若是第一种状况没有设置值,则其值为0。可使用rawValue
属性访问枚举项的原始值。
enum Planet: Int,CaseIterable {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
//查看各项的`rawvalue`
var planetOutStr = "枚举类型Planet各项的原始值"
for item in Planet.allCases {
planetOutStr += "\(item) : \(item.rawValue) "
}
print(planetOutStr)//!< 枚举类型Planet各项的原始值mercury : 1 venus : 2 earth : 3 mars : 4 jupiter : 5 saturn : 6 uranus : 7 neptune : 8
复制代码
原始值为字符串类型的枚举,每一个枚举项隐式分配的原始值是该枚举项的名称。
enum CompassPoint :String,CaseIterable{
case north,west,east,south
}
var directionOutStr = "枚举类型CompassPoint各项的原始值"
for item in CompassPoint.allCases {
directionOutStr += "\(item) : '\(item.rawValue)' "
}
print(directionOutStr)//!< 枚举类型CompassPoint各项的原始值north : 'north' west : 'west' east : 'east' south : 'south'
复制代码
从原始值初始化
若是使用原始值类型定义枚举,则枚举会自动接收一个参数名:rawValue
参数类型:原始值类型的初始话方法,并返回枚举项或nil
。咱们可使用此初始化方法尝试建立该枚举类型的新实例。
let possiblePalnet = Planet.init(rawValue: 7)
//!< Planet类型的可选项。Optional(swift_basic.EnumerationPractice.Planet.uranus)
//没法根据原始值匹配到枚举项的状况
let possiblePalnet = Planet.init(rawValue: 9)//!< Planet类型的可选项。9已经超出了枚举的全部项的范围。log:nil
//须要解包,可选绑定
if let possiblePlanet = possiblePalnet {
print(possiblePlanet)
switch possiblePlanet {
case .earth:
print("地球")
default:
print("其余行星")
}
} else {
print("没有找到合适的枚举项")
}
复制代码
定义一个枚举时,若该枚举类型的某个case
关联了一个或多个该枚举类型的值时,系统会自动提示,须要添加indirect
关键字,由于此时的枚举类型已经被定义为了拥有递归结构的递归枚举。 经过在枚举项的前面使用indirect
关键字,来表示此枚举项是可递归的。 如下示例为存储了三个数学表达式递归枚举的定义。
//方式一
//递归枚举,存储了三个数学表达式 使用`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)
}
复制代码
ArithmeticExpression
枚举类型的每一项都设置有相应的关联值,而且addition
和multiplication
都关联了能够存储(ArithmeticExpression, ArithmeticExpression)
类型的值。即:分别关联了两个ArithmeticExpression
枚举类型。
递归枚举的嵌套:
//存储了一个为5的关联值
let five = ArithmeticExpression.number(5)
//存储了一个为6的关联值
let six = ArithmeticExpression.number(6)
//存储了一个为3的关联值
let three = ArithmeticExpression.number(3)
//addition枚举项,关联了两个当前枚举类型的值。
let sum = ArithmeticExpression.addition(five, six)
//multiplication枚举项,关联了两个当前枚举类型的值。
let multiplication = ArithmeticExpression.multiplication(sum, three)//数学表达式的呈现形式。
复制代码
建立递归函数验证multiplication
是否能够计算正确结果
//建立一个递归函数验证可递归性
func arithmeticOperation(_ expression : ArithmeticExpression) -> Int {
switch expression {
case let .number(x):
return x
case let .addition(x, y):
//! 此处x和y仍旧是表达式,因此须要先进行递归运算得出`Int`类型的关联值
return arithmeticOperation(x) + arithmeticOperation(y)
case .multiplication(let x, let y):
//! 此处x和y仍旧是`ArithmeticExpression`,因此须要先进行递归运算得出`Int`类型的关联值
return arithmeticOperation(x) * arithmeticOperation(y)
}
}
print("嵌套的数学表达式进行递归调用后的结果是:\(arithmeticOperation(multiplication))")
//!< log:嵌套的数学表达式进行递归调用后的结果是:33
复制代码
参考资料: swift 5.1官方编程指南
了解更多iOS及相关新技术,请关注咱们的公众号:
小编微信:可加并拉入《QiShare技术交流群》。
关注咱们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)
推荐文章:
iOS 给UILabel添加点击事件
用SwiftUI给视图添加动画
用SwiftUI写一个简单页面
Swift 5.1 (7) - 闭包
iOS App启动优化(三)—— 本身作一个工具监控App的启动耗时
iOS App启动优化(二)—— 使用“Time Profiler”工具监控App的启动耗时
iOS App启动优化(一)—— 了解App的启动流程
奇舞周刊