枚举
枚举
的基本用法
enum Direction {
case north
case south
case east
case west
}
等价于
enum Direction {
case north,south,east,west
}
var dir = Direction.west
dir = Direction.east
dir = .north
print(dir) /// north
switch dir {
case .north:
print("north")
case .south:
print("south")
case .east:
print("east")
case .west:
print("west")
}
关联值
有时会将枚举的成员值
跟其他类型的关联存储
在一起,会非常有用
enum Score {
case points(Int)
case grade(Character)
}
var score = Score.points(96)
score = .grade("A")
switch score {
case let .points(i):
print(i,"points")
case let .grade(i):
print("grade",i)
}
/// 打印结果:grade A
enum Date {
case digit(year: Int , month: Int , day: Int)
case string(String)
}
var date = Date.digit(year: 2020, month:12, day: 12)
date = .string("2020-01-01")
switch date {
case .digit(let year,let month, let day) :
print(year,month,day)
case let .string(value)
print(value)
}
原始值(Raw Value)
枚举成员可以使用相同类型的默认值预先关联
,这个默认值叫做: 原始值
/// : String 是指枚举关联原始值的类型
enum PokerSuit : String {
case spade = "黑桃"
case heart = "红心"
case diamond = "方块"
case club = "梅花"
}
var suit = PokerSuit.spade
print(suit) /// spade
print(suit.rawValue) /// 黑桃
print(PokerSuit.club.rawValue) /// 梅花
隐式原始值
如果枚举的原始值是Int,String
,Swift会自动分配
原始值
/// 如果原始值的类型是String,那么Swift默认会将其`成员值`作为`原始值字符串`
enum Direction : String {
case north
case south
case east
case west
}
等价于
enum Direction : String {
case north = "north"
case south = "south"
case east = "east"
case west = "west"
}
enum Season : Int {
case spring, summer , autumn , winter
}
print(Season.spring.rawValue) /// 0
print(Season.summer.rawValue) /// 1
print(Season.autumn.rawValue) /// 2
print(Season.winer.rawValue) /// 3
enum Season : Int {
case spring = 1, summer , autumn = 4 , winter
}
print(Season.spring.rawValue) /// 1
print(Season.summer.rawValue) /// 2
print(Season.autumn.rawValue) /// 4
print(Season.winer.rawValue) /// 5
MemoryLayout
可以使用
MemoryLayou
t获取数据类型占用的内存大小
var age = 10
MemoryLayout.size
MemoryLayout.stride
MemoryLayout.alignment
等价于
MemoryLayout.size(ofValue:age)
MemoryLayout.stride(ofValue:age)
MemoryLayout.alignment(ofValue:age)
enum Password {
case number(Int, Int , Int, Int)
case other
}
MemoryLayout.size /// 33 , 实际使用的空间大小
MemoryLayout.stride /// 40 ,分配占用的空间大小
MemoryLayout.alignment /// 8 , 对齐参数
可选项Optional
可选项,一般也叫可选类型,它
允许将值设置为nil
在类型名称后面加个问号?
来定义一个可选项
/// 这样定义一个变量,是没有默认值的,而且不可以将其设置为nil
var age: Int
/// age 是可选类型,默认值是nil
var age: Int?
等价于
var age: Int? = nil
var name: String? = "Jack"
name = nil
var array = [1,15,40,29]
func get(_ index: Int) -> Int? {
if index < 0 || index >= array.count {
return nil
}
return array[index]
}
print(get(1)) /// Optional(15)
print(get(-1)) /// nil
强制解包
可选项是对其他类型的一层包装
,可以将它理解为一个盒子
如果为nil,那么它就是个空盒子
如果不是nil,那么盒子里装的是: 被包装类型的数据
如果要从可选项中取出被包装的数据(将盒子里装的东西取出来),需要
使用感叹号!进行强制解包
var age: Int? = 10
let ageInt: Int = age!
ageInt += 10
如果对值为
nil
的可选项(空盒子)进行强制解包
,将会产生运行时错误
let number = Int("123")
if number != nil {
print("字符串转换整数成功: \(number!)")
}else{
print("字符串转换整数失败")
}
可选项绑定
可以
使用可选项绑定来判断可选项是否包含值
如果包含就自动解包
,把值赋给一个临时的常量(let)或者 变量(var),并返回true
,否则返回false
if let number = Int("123") {
print("字符串转整数成功:\(number)")
/// number 是强制解包之后的Int值
/// number 作用域仅限于这个大括号
} else {
print("字符串转换整数失败")
}
enum Season : Int {
case spring = 1, summer, autumn, winter
}
if let season = Season(rawValue: 6) {
switch season {
case .spring :
print("the season is spring")
default :
print("the season is other")
}
} else {
print("no such season")
}
if let first = Int("4") {
if let second = Int("42") {
if first < second && second < 100 {
print("\(first) < \(second) < 100")
}
}
}
等价于
/// 注意: 这里是用逗号, 隔开的,不能使用 && ,因为这里使用可选项绑定
/// 这是语法规定的
if let first = Int("4"),
let second = Int("42"),
first < second && second < 100 {
print("\(first) < \(second) < 100")
}
while 循环中使用可选项绑定
/// 遍历数组,将遇到的正数都加起来,如果遇到了负数或非数字,停止遍历
var strs = ["10","20","abc","-10","30"]
var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
sum += num
index += 1
}
print(sum)
空合并运算符??
a ?? b
a 是 可选项
b 是 可选项 或者 不是可选项
b 跟 a 的存储类型必须相同
如果 a 不为 nil, 就返回a
如果 a 为 nil, 就返回b
如果b 不是可选项
,返回a时会自动解包
let a: Int? = 1
let b: Int? = 2
let c = a ?? b // 结果:c是Int? , Optional(1)
let a: Int? = nil
let b: Int? = 2
let c = a ?? b // 结果:c是Int? , Optional(2)
let a: Int? = nil
let b: Int? = nil
let c = a ?? b // 结果:c是Int? , nil
let a: Int? = 1
let b: Int = 2
let c = a ?? b // 结果:c是Int , 1
let a: Int? = 1
let b: Int = 2
let c = a ?? b ?? 3 // 结果:c是Int , 1
?? 跟 if let 配合使用
let a : Int? = nil
let b : Int? = 2
if let c = a ?? b {
print(c)
}
/// 类似于 if a != nil || b != nil
if let c=a , let d =b {
print(c)
print(d)
}
/// 类似于 if a != nil && b != nil
/// 实例
func login(_ info: [String : String]) {
let username: String
if let tmp = info["username"] {
username = tmp
}else {
print("请输入姓名")
return
}
let password : String
if let tmp = info["password"] {
password = tmp
}else {
print("请输入密码")
return
}
print("用户名: \(username) 密码: \(password) ",“登录ing”)
}
隐式解包
在某种情况下,可选项一旦被设定值之后,就
会一直拥有值
在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值
可以在类型后面加个感叹号!
定义一个隐式解包的可选项
/// num1 依然是一个可选项,不过当它遇到Int类型的时候,会自动解包
/// 注意: num1 不能为nil,因为nil解包会报错
let num1: Int! = 10
let num2: Int = num1
if num1 != nil {
print(num1 + 6)
}
guard 语句
当
guard
语句的条件为false
时,就会执行
大括号里面的代码
当guard
语句的条件为true
时,就会跳出
guard语句
gurad语句特别适合用来“提前退出”
gurad 条件 else {
/// do something...
退出当前作用域
/// return 、break、continue、throw error
}
当guard语句进行可选项绑定时,绑定的常量、变量也能在外层作用域中使用
func login(_ info: [String: String]) {
guard let username = info["username"] else {
print("请输入用户名")
return
}
guard let pasword = info["password"] else {
print("请输入密码")
return
}
print("用户名: \(username) 密码: \(password) ",“登录ing”)
}