Swift -- 03 可选项、空合并运算符、guard

685 阅读5分钟

swift.webp

可选项

1、定义可选项

在Swift中,默认情况下,不能给变量设置为空值
如果需要赋空值,需要将变量定义为可选类型

可选项,一般也叫可选类型,它允许将值设置为nil;
在类型名称后面增加?来定义为可选类型;如:

var str : String? = "QLY"
str = nil
var age : Int?  //默认为 nil
age = 20
age = nil

可选类型,是对其他类型的一层包装,可以理解为一个盒子,盒子里包含数据;
如果为nil,就是个空盒子;
如果不为nil,盒子里装的就是被包装的数据类型;
1.png

2、强制解包(可选项取值)

获取可选项变量的值,需要对可选项进行强制解包
使用感叹号 ! 进行强制解包\

var str : String? = "WL"
print(str!)

注意⚠️:不能对空值进行强解包

var str : String?
print(str!)

判断可选项,是否有值:

var str : String?
if str != nil {
    print("有值")
} else {
    print("为nil")
}

3、可选项绑定

可以使用可选项绑定来判断可选项是否包含值;
如果包含,将自动解包,把值赋给临时常量(let)或变量(var),并返回true,否则返回false;

//判断Int("123")是否转换成功,不为nil
if let numner = Int("123")
{
    print("字符串转换为整数\(numner)")
}else {
    print("字符转转换失败")
}

我们有多重条件判断时,常规的写法是这样的:

if let first=Int("3"){
    if let section = Int("34") {
        if first < section && section < 100 {
            print("条件成功")
        }
    }
}

但是这样的写法,代码不美观,Swift提供了另一种简洁、等价的写法:

if let first=Int("3"),let section = Int("34"),first < section && section < 100{
    print("条件成功")
}

有了这种等价写法,在多重条件判断时,将更加方便使用;
例子:

var numbers = ["12","34","-31","3","6"]
var sum = 0
var index = 0

//循环numbers里的数据,当num < 0的时候,跳出while循环
while let num = Int(numbers[index]),num>0
{
    sum += num
    index += 1
}
print("sum = \(sum)")

4、隐式可选项

在某些情况下,可选项设值之后,就会一直存在值,不会为空,这种情况下,可以去掉检查,也不必每次访问的时候,都进行解包,因为它能确定一直有值;
那么这种情况,我们可以在类型后面添加!(感叹号),定义为隐式可选项;

    let num1 : Int! = 1
    let num2 : Int = num1
    // num1 是隐式可选项,所以可以直接赋值给num2
    // 如果num1 是可选项,赋值给num2的时候,需要进行强制解包

使用场景:

  • 确保一个常量、变量一直有值的话,在声明常量、变量的时候,可以声明为隐式可选项;
  • 注意,隐式可选项,也是可选项,所以隐式可选项为 nil 的时候,是不能进行强制解包的

5、多重可选项

多重可选项是使用?? 来声明

1、注意,多重可选项的 ??空合并运算符的 ?? 是不一样的;
2、多重可选项的 ??是用来定义类型的;

let num1:Int? = 10 //相当于盒子里,包装了一个Int类型的可选类型
let num2:Int?? = num1//相当于盒子里,包装了一个可选类型的可选类型
let num3:Ing?? = 10

图示: iShot2022-04-22_16.05.00.jpg

注意⚠️⚠️:如果num1、num2、num3为nil 呢?

let num1:Int? = nil 
let num2:Int?? = num1
let num3:Ing?? = nil

那么,num1、num2、num3盒子里,是不一样的;

iShot2022-04-22_16.06.55.jpg

例题:

let num1:Int? = nil 
let num2:Int?? = num1
let num3:Ing?? = nil

1(num2 ?? 1) ?? 2 
答案:2

解答:
先比较:(num2 ?? 1);
num2 = num1,所以num2 不为nil,所以这里返回 num2,但由于1是不可选类型,所以返回num2需要进行解包,解包后得到的值就是num1;
再比较  num1 ?? 2 ,由题可知,num1 = nil,所以直接返回 22(num3 ?? 1) ?? 2 
答案:1
解答:先比较 (num3 ?? 1) ,num3 = nil,直接返回1;
再比较 1 ?? 21 不为nil,直接返回 1

双重强制解包 定义一个多重可选项,可以进行多次解包,由此可以验证,多种可选项,盒子里包含的数据类型

iShot2022-04-22_16.22.09.jpg

iShot2022-04-22_16.22.35.jpg

空合并运算符??

1、定义

public func ?? <T>(optional: T?,defaultValue:@autoclosure () throws -> T?) rethrows -> T?
public func ?? <T>(optional: T?,defaultValue:@autoclosure () throws -> T) rethrows -> T

2、使用

使用方式:\color{#9B0509}{使用方式:} a ?? b

  • a 必须为可选项
  • b 可以是可选项或者非可选项
  • a、b的存储类型必须相同;
  • 如果a 不为 nil,则返回 a;
  • 如果a 为 nil,则返回 b;
  • 如果b 不是可选项,返回a时将自动解包
let a : Int? = 1
let b : Int? = 2

let c = a ?? b

//当 a != nil,并且为可选项时, c 返回a,是 Int?类型,c = Optional(1)
//当 a = nil,b为可选项时,c 返回 b,是 Int?类型,c = Optional(2)
//当 a != nil,b为不可选项时,c 返回 a,c 自动解包,是 Int类型,c = 1

?? 也可多个一起使用:

let a : Int? = nil
let b : Int? = 2

let c = a ?? b ?? 5

// 先执行 a ?? b ,得到值后,再用得到的 值 ?? 5 

guard 条件判断语句

guard语句与if语句一样,都是控制流语句,都是基于表达式的布尔值去判断是否要执行某一段代码;

区别在于\color{#9B0509}{区别在于}
1、guard 语句条件不满足的时候,才执行大括号里的代码;
2、guard 语句条件为true时,就会跳出guard语句;
3、guard 语句适合用来提前退出
4、guard 语句进行可选项绑定时,绑定的常量(let)、变量(var)也可以在外层作用域中使用;

使用例子:

guard 条件 else {
    //do something
    
    //使用如下关键字,可以退出当前作用域
    //return、break、continu、throw error
}
//使用guard判断用户名、密码是否存在,login 函数内部,可以使用用户名、密码这两个参数;
func login(_ info:[String:String])
{
    guard let username = info["username"] else {
        print("请输入用户名")
        return
    }
    
    guard let passwork = info["passwork"] else {
        print("请输入密码")
        return
    }
    print("用户名 = \(username),密码 = \(passwork)")
}