和结构体一样,swift中的枚举也是值类型。除了定义一个或多个case成员,还可以做以下事情:
- 可以定义方法,计算属性,下标
- 可以通过mutating定义可变方法
- 可以扩展,遵守协议,支持范型
和结构体的唯一区别就是枚举不能定义存储属性
1. 枚举的语法:
enum TextAlignment{
case left
case right
case center
}
//或者 写在一行
enum TextAlignment{
case left, right, center
}
2. 遵守协议&遍历枚举值
例如:系统自带的CaseIterable协议,allCases属性列出所有的枚举成员,也可以通过手动添加计算属性或方法达到同样的目的,对于没有关联值的枚举,编译器会自动为其实现allCases(成员顺序和声明时候一致)
extension TextAlignment:CaseIterable{}
TextAlignment.allCases // left right center
// 或者 手动添加计算属性
extension TextAlignment {
static var allCases: [TextAlignment] {
[.left,.right,.center]
}
}
3. 原始值、隐式赋值
C或Objective-C中的枚举,是可以通过0 1 2 3...来初始化和使用。Swift枚举默认不会为每个成员分配0 1 2 3...也不能通过整数初始化枚举。要想获得这种特性,必须添加原始值。语法如下
enum TextAlignment:Int {}
原始值可以是字符串、字符或任何整数或浮点数类型。但是每个值对应的原始值必须是唯一的。
enum TextAlignment:String {
case left = "0"
case right = "1"
case center = "2"
}
通过rawValue创建的枚举值是可选的?
var aligent = TextAlignment(rawValue:"1")
// Optional(TextAlignment. right)
RawRepresentable
协议
实现
RawRepresentable
协议的类型会获得两个新的 API:一个 rawValue 属性和一个可失败的初始化方法 (init?(rawValue:)),编译器自动为具有原始值的枚举实现这个协议。
编译器会通过递增前一个成员的原始值来给下一个枚举成员赋值。
enum TextAlignment:Int{
case left
case right
case center
}
// 系统会自动分配 0 ,1,2给成员
var alignment : TextAlignment = .center
alignment.rawValue // 2
原始值是String的时候,默认情况下系统用 case 值来初始化枚举原始值:
enum TextAlignment:String{
case left
case right
case center
}
var alignment: TextAlignment = .left
print(alignment.rawValue) // "left"
4. 枚举关联值
原始值与关联值不同,枚举成员一旦设置了原始值使用中就不能在变,关联可以根据使用变化。
一个确定枚举值加上其关联值可以使的该枚举类型有更多的成员,Swift可以枚举成员关联任意类型的值
enum TextAlignment{
case left(String)
case right(String)
case center(CGFloat,CGFloat)
}
5. 枚举支持范型&关联值
范型是Swift最强大的功能之一,Swift标准库的大部分都是用通用代码构建的。它能使您编写灵活、可重用的函数和类型,这些函数和类型可以根据您定义的要求适用于任何类型,避免重复的代码。
关于枚举的范型,看如下的例子:
定义范型枚举Result
// 定义范型枚举Result
enum Result<Success, Failure>{
case success(Success)
case failure(Failure)
}
使用Result
struct LError:Error{
var message = "错误信息"
}
// 网络请求结果
var result:Result<Dictionary, LError > = .success(["code":"200"])
// 失败时
result = .failed(LError(message: "404"))
//通过switch匹配结果
switch result{
case.success(let data):
print(data)
case.failed(let error):
let ler = error as! LError
print(ler.message)
}
实际上,范型枚举都是和关联值结合使用的。Swift自带的Result类型也是这种形式的枚举。
假如我们要从本地磁盘读取文件,这个过程可能会失败,可以设定读取结果可选?这样以来,读取失败就会返回nil,但是我们不知道失败的原因,Result就可以表达那些需要提供详细信息的错误。如果我们不关注错误原因,直接忽略failed后面的关联值即可(下文有讲述如何忽略关联值)。
- 枚举使用就简单介绍到这里,接下来重点看枚举的使用和模式匹配。
Swift 要求枚举必须考虑到每一种情况,最常用方法就是使用 switch 语句
普通枚举,没有关联值的情况
var aligent:TextAlignment = .left
// 模式匹配 ,所有情况 left, right,center
switch aligent{
case .left:
break
case .right:
break
case .center:
break
}
通配符 _ ,下划线匹配任意值并忽略这个值,等同default
// default 忽略
switch aligent {
case .left:
break
default:
break
}
// 通配符 _
switch aligent {
case .left:
break
case _ :
break
}
匹配多个值的情况,多个枚举值可以写在一行,也可以使用通配符_,default。
// 匹配多个的情况
switch aligent {
case .left,.right:
break
case .center:
break
}
除了switch之外,也可以用if 和if case 匹配
if aligent == .left{
// do ...
}
if case .left = aligent {
// do ...
}
值绑定模式,像处理可选值一样,可以把枚举的关联值绑定到一个let or var 声明的变量上,带关联值的枚举如下:
var aligent1:TextAlignment = .left("left")
var aligent2:TextAlignment = .center(0, 0)
// 值绑定模式
switch aligent1 {
case .left(let string): //绑定到变量 string
break
case .right(let string):
break
case .center(let x, let y): //绑定到变量x,y
break
}
// let写在前面也是可以的
switch aligent1 {
case let.center(x, y):
break
case let.right(str):
break
case _:
break
}
如果想忽略关联值,可以按照编译器提示用下划线_忽略,或者不写后面的括号()
// 用下划线_忽略
switch aligent1 {
case .left(_):
break
case .right(_):
break
case .center(_,_):
break
}
// 不写后面的括号()
switch aligent1 {
case .left:
break
case .right:
break
case .center:
break
}
关联值有单个or多个,匹配确定的关联值。
// 匹配确定的关联值 center(x,y)中的x=0,y=0的情况
switch aligent1 {
case .center(0,_):
break
case _:
break
}
// 只匹配确定的关联值 center(x,y)中的x=0的情况
switch aligent1 {
case .center(0,_):
break
case _:
break
}