可选项,一般也叫可选类型,它允许将值设置为nil
在类型名称后加个问号?来定义一个可选项
var name: String?
name = nil
// 默认是nil
var age: Int?
age = 10
强制解包
可选项是对其他类型的一层包装,可以将它理解为一个盲盒
如果为nil,那么它是个空盒子
如果不为nil,那么盒子里装的是:被包装类型的数据
如果要从可选项中取出被包装的数据(将盒子里装的东西取出来),需要使用感叹号!进行强制解包(拆盲盒)。
var age: Int? = 10
var ageInt: Int = age!
ageInt += 10
如果对值为nil的可选项(空盒子)进行强制解包,将会产生运行时错误
var age: Int?
var ageInt: Int = age!
Fatal error: Unexpectedly found nil while unwrapping an Optional value
判断可选项是否包含值
var num = Int("abc")
if num != nil {
print("num = \(num!)")
}else {
print("num = nil")
}
可选项绑定(Optional Binding)
可以使用可选项绑定来判断可选项是否包含值
如果包含就自动解包,把值符给一个临时的常量(let)或者变量(var),并返回true,否则返回false
if let number = Int("123") {
print("number - \(number)")
}else {
print("number 转换成整数失败")
}
上面代码是固定写法,Int(“123”)会尝试解包,并复制给number,如果成功了,则返回true,进入条件成功的判断,如果Int(“123”)是空,则返回false,进入条件失败的判断,number的作用域也仅限于条件成功的大括号内。
等价写法
if let first = Int("1") {
if let second = Int("2") {
print("first = \(first), second = \(second)")
}
}
if let first = Int("1"), let second = Int("2") {
print("first = \(first), second = \(second)")
}
while循环中使用可选项绑定
// 遍历数组,将遇到的整数都加起来,如果遇到负数或者非数字,停止遍历
var strs = ["10", "20", "abc", "-10", "-20"]
var sum = 0
var index = 0
while let num = Int(strs[index]), num > 0 {
sum += num
index += 1
}
print("sum = \(sum)")
空合并运算符 ??(Nil-Coalescing Operator)
a ?? b
a 是可选项
b 是可选项 或者 不是可选项
b 跟a的存储类型必须相同
如果a不为nil,就返回a
如果a为nil,就返回b
如果b不是可选项,返回a时会自动解包
// 情况1:如果a不为nil,就返回a
var a: Int? = 1
var b: Int? = 2
let c = a ?? b // c是Int?, Optional(1)
// 情况2:如果a为nil,就返回b
var a: Int? = nil
var b: Int? = 2
let c = a ?? b // c是Int?, Optional(2)
var a: Int? = nil
var b: Int? = nil
let c = a ?? b // c是nil
// 情况3:如果b不是可选项,返回a时会自动解包
var a: Int? = 1
var b: Int = 2
let c = a ?? b // c是Int, 1
总结:如果b是可选项,则返回的是可选项,如果b是不可选项,则返回的是不可选项
多个 ??一起使用
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)
}
guard语句
guard 条件 else {
// do something
退出当前作用域
// return、break、continue、throw error
}
当guard语句的条件为false时,就回执行大括号里面的代码
当guard语句的条件为true时,就回跳过guard语句
guard语句特别适合来“提前退出”
当使用guard语句进行可选绑定时,绑定的常量、变量也能在外层作用域中使用
func login(_ info: [String : String]) {
guard let username = info["username"] else {
print("请输入用户名")
return
}
guard let password = info["password"] else {
print("请输入密码")
return
}
print("用户名 = \(username), 密码:\(password)")
}
隐式解包(implicity Unwrapped Optional)
在某些情况下,可选项一旦被设定值后,就会一直拥有值
在某些情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值
可以在类型后面加个感叹号!定义一个隐式解包的可选项
let a: Int! = 10
let b: Int = a
print(b) // Int, 10
无论?还是!都代表可选项,只是!会在访问数据时自动解包
如果可选项时空值,会报错。
开发中尽量不要使用隐式解包和强制解包
字符串插值
可选项在字符串插值或者直接打印时,编译器会发出警告
let a: Int? = 10
print(a)
print("a = \(a)")
至少有三种方法消除警告
// 1、强制解包
print("a = \(a!)") // a = 10
// 2、打印描述字符串
print("a = \(String(describing: a))") // a = Optional(10)
// 3、使用??
print("a = \(a ?? 0)") // a = 10
多重可选项
// 包装了一个可选类型(一个盲盒)
var a: Int? = 10
// 包装了一个可选类型的可选类型(盲盒里面有一个盲盒)
var b: Int?? = a
// 系统会自动包装成和b一样的结构
var c: Int?? = 20
a如下图所示:
b如下图所示:
c和b的结构一致
var a: Int? = 10
var b: Int?? = a
// 如果直接赋值为空,则内部为空值
var c: Int?? = nil
c的结果如下图所示: