可选项
可选项就是一个变量可以置为nil,在Swift中普通的变量是不能置为nil的,只有可选类型才能将变量置为nil,而且非可选类型的变量初始化的状态也不是nil。可选项其实是相当于对数据重新包装了一层来解决变量为nil的问题,就好像vue3将数据包装一层,来让他有响应式一样。
Optional 是 Swift 中用于表示“有值或无值”的一种强类型系统机制,提升了代码的安全性和可读性。
可选项是对其他类型的一层包装,可以将它理解为一个盒子。如果为nil,那么它是一个空盒子。如果不为nil,那么盒子里面装的是:被包装类型的数据
普通用法
var age:Int? // 默认就是nil
age = 10
age = nil
var array = [1,15,40,29]
func get(_ index:Int) -> Int? {
if index < 0 || index >= array.count {
return nil
}
return array[index]
}
print("111")
print(get(1))
print(get(-1))
print(get(4))
强制解包
如果要从可选项中取出被包装的数据(将盒子里面的东西取出来),要使用感叹号!进行强制解包
var age2: Int? = 10
var ageInt: Int = age2!
如果对值为nil的可选项(空盒子)进行强制解包,会产生运行时错误
var age3:Int?
age3!
真是因为如果你对可选项强制解包,如果可选项的值为nil,程序就会运行崩溃,所以在强制解包前要判断包内的东西是不是nil,所以强制解包前要先判断。所以如果用强制解包,写法应该按照下面写法。
let number = Int("123")
if number != nil {
print("字符串转换整数成功:\(number!)")
} else {
print("字符串转换整数失败")
}
可选项绑定
可选性绑定可以根据可选项绑定来判断可选项是否包含值 如果包含就自动解包,把值赋给一个临时的变量(let)或者变量(var),并且返回true.否则返回false
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("\(second) < \(second) < 100")
}
if (6 > 5){
print("hello World")
}
下面是在while循环中的使用
var strs = ["10","20","abc","-20","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的时候就会自动解包。
如果多个 ??连用,最后的返回值是最后一个类型的参数类型,值是从前往后看的第一个不为nil的值
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)
}
guard语句
guard 条件 else {
//do someting
退出当前作用域
// return, break,continue,throw error
}
- 当guard 语句的false时,就会执行大括号里面的代码
- 当guard语句的条件为true时,就会跳过guard 语句
guard 语句特别适合用来 “提前退出” 使用guard 语句进行可选项绑定时,绑定的常量(let),变量(var)也能在外层作用域中使用
下面举一个不用guard的情况
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")
}
如果我使用guard应该用下面的写法
func login1(_ info:[String :String]){
guard let username = info["username"] else {
print("请输入用户名")
return
}
guard let password = info["password"] else {
print("请输入密码")
return
}
print("用户名:\(username)","密码:\(password)","登录ing")
}
隐式解包
- 在某些情况下,可选项一旦被设定值之后,就会一直拥有值。在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值。可以在类型后面加个感叹号! 定义一个隐式解包的可选项。
- 隐式可选项可以简单的理解为了不每次使用都去解包,一个是麻烦,另外一个是没有必要采取的一种措施。 下面是隐式解包的具体使用
let num2: Int! = 10
let num3:Int = num2 + 2
print("num3",num3)
// 这里其实就是普通的判断
if num2 != nil {
// 下面可以直接用是因为隐式解包
print(num2 + 10)
}
// 这其实是可选绑定
if let num3 = num2 {
print(num3)
}
可选项的打印问题
可选项在字符串插值或者直接打印时,编译器会发出警告
var age5:Int? = 10
print("My age is\(age5)")
上面的打印会有警告,下面的方式可以消除警告
print("My age is \(age5!)")
print("My age is\(String(describing: age5))")
print("My age is \(age5 ?? 0)")
多重可选项
情况1
var num4: Int? = 10
上面可以简单看做 num4 这个变量里面装了一个盒子,盒子的类型是 Int? 类型,里面的数据是4
情况2
var num5: Int?? = num4
上面可以看做 num5 这个变量里面装了一个盒子,盒子的类型是 Int??类型,盒子里面有套了一个盒子,这个盒子是 Int?类型,然后最里面的盒子里面的放的是 10
情况3
var num6: Int?? = 10
print(num5 == num6) // true
和上面的例子是一样的