JHHK

欢迎来到我的个人网站
行者常至 为者常成

3_2、可选项

目录

可选项

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

func optionalUse() -> Void {
    //1、设置nil

    //直接设置 nil会报错
    //var name:String = nil

    //name可存储两种类型  String和nil
    var name:String? = nil
    name = "jack"
    name = nil

    //age可存储两种类型  Int和nil
    var age:Int? = nil
    age = 18
    age = nil

    //默认nil
    var weight:Int?
    weight = 80
    weight = nil

    //应用
    var array = [1,2,3,4]

    func get(_ index:Int)->Int?{
        if index<0 || index>=array.count {
            return nil
        }
            
        return array[index]
    }

    print(get(1))//Optional(2)
    print(get(1)!)//2
    
    //对 空 进行解包 会报错 Fatal error: Unexpectedly found nil while unwrapping an Optional value
    //print(get(10)!)
    print(get(10))//nil
    print(get(-1))//nil
}

强制解包

可选项是对其他类型的一层包装,可以将它理解为一个盒子
如果为nil,那么它是个空盒子
如果不为nil,那么盒子里装的是:被包装类型的数据

var age: Int? // 默认就是nil         
age = 10         
age = nil 

如果要从可选项中取出被包装的数据(将盒子里装的东西取出来),需要使用感叹号 ! 进行强制解包
如果对值为nil的可选项(空盒子)进行强制解包,将会产生运行时错误

var age: Int? = 10         
let ageInt: Int = age!         
ageInt += 10       

代码演示

func unwrappingUse() -> Void {
    //1、解包
    let age2:Int? = 10
    //let age22:Int = age2//这么写会报错
    let age22:Int = age2! //10
    print(age22)


    //2、对nil 进行强制解包会报错
    let age23:Int? = nil
    //print(age23!)//报错


    //3、判断可选项是否包含值
    let num = Int("123")

    if num != nil{
        print("字符串转换成功",num!)
    }else{
        print("字符串转换失败")
    }
}

可选项绑定

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

1、if let 会对可选项自动解包

if let num3 = Int("123") {
    print("字符串转换成功",num3)
}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")
}

2、以下两种写法等价

if let first = Int("4") {
    if let second = Int("42") {
        if first<second && second<100 {
            print(first,second)
        }
    }
}

if let first = Int("4"),
    let second = Int("42"),
first<second && second < 100 {
    print(first,second)
}

3、while循环中

//遍历数组将遇到的正数加起来,遇到非数字或负数停止遍历
let str = ["10","20","abc","-10","30"]
var sum4 = 0
var index4 = 0
while let num = Int(str[index4]),num>0 {
    sum4 += num
    index4 += 1
}
print(sum4)

空合并运算符

b 跟 a 的存储类型必须相同

a是可选项 b是可选项 返回可选项
a 非nil 返回 a
a 为nil 返回 b
a是可选项 b非可选项 返回非可选项
a 非nil 返回 a!
a 为nil 返回 b

重点:
a决定了返回谁 b决定了返回什么类型

func emptyMerge(){
    //1、基本使用1
    print("------------基本使用1_1-------------")
    do{
        //a是可选项 b是可选项
        let a:Int? = 1
        let b:Int? = 2
        let c = a ?? b
        print(c)//Optional(1)
    }
    
    //2、基本使用2
    print("------------基本使用1_2-------------")
    do{
        //a是可选项 b是可选项
        let a:Int? = nil
        let b:Int? = 2
        let c = a ?? b
        print(c)//Optional(2)
    }
    
    
    //2、基本使用2
    print("------------基本使用2_1-------------")
    do{
        let a:Int? = 1
        let b:Int = 2
        let c = a ?? b
        print(c)//1
    }
    
    print("------------基本使用2_2-------------")
    do{
        let a:Int? = nil
        let b:Int = 2
        let c = a ?? b
        print(c)//1
    }

    
    


    //3、多个 ?? 一起使用
    print("------------多个 ?? 一起使用-------------")
    do{
        let a:Int? = 1
        let b:Int? = 2
        let c = a ?? b ?? 3
        print(c)//1
    }


    //4、 if let 和 ??配合使用
    print("------------if let 和 ??配合使用-------------")
    do{
        //类似于 if a != nil || b != nil
        let a:Int? = nil
        let b:Int? = 2
        if let c = a ?? b {
            print(c)//2
        }else{
            
        }
    }
    
    do{
        let a:Int? = 1
        let b:Int? = 2
        //类似于 if a != nil && b != nil
        if let c = a, let d = b {
            print(c,d)//1 2
        }else{
            
        }
    }
}

guard语句

字典内取出的value是 可选项类型

1、if let 语句实现登录

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)")
}

login(["username":"jack","password":"123456"])
login(["username":"jack"])
login(["password":"123456"])

2、guard语句实现

//当使用guard语句进行可选项绑定时,绑定的常量let 变量var 也能在外层作用域中使用
func login2(_ info:[String:String]){
    
    /*
        guard 条件 else {
        // do something....
        退出当前作用域
        // return、break、continue、throw error
        }
        
        当guard语句的条件为false时,就会执行大括号里面的代码
        当guard语句的条件为true时,就会跳过guard语句
        
        guard语句特别适合用来“提前退出”
        当使用guard语句进行可选项绑定时,绑定的常量(let)、变量(var)也能在外层作用域中使用
    */

    guard let userName = info["username"] else {
        print("请输入用户名")
        return
    }
    
    guard let passWord = info["password"] else {
        print("请输入密码")
        return
    }
    
    print("username:\(userName)","password:\(passWord)")
}

login2(["username":"jack","password":"12345"])

login2(["username":"jack"])

login2(["password":"12345"])

login2(["hello":"sss"])

隐式解包

func hideUnWrapping(){
    
    /*
    在某些情况下,可选项一旦被设定值之后,就会一直拥有值
    在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值
    可以在类型后面加个感叹号 ! 定义一个隐式解包的可选项
    */
    
    do{
        let num1:Int! = 10
        let num2:Int = num1

        if num1 != nil {
            print(num1+6)
        }

        if let num3 = num1 {
            print(num3)
        }
    }
    
    do{
        let a:Int! = nil
        
        //nil无法解包
        //报错:Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
        //let b:Int = a
    }
}

字符串插值

func stringInsert() -> Void {
    let age:Int? = 10
    print("age is \(age)")
    
    //有几种方法可以消除警告
    print("age is \(age!)")
    
    print("age is \(age ?? 0)")
    
    print("age is \(String(describing: age))")
}

多重可选项

func multipleOptional1(){
    let num1:Int? = 10
    let num2:Int?? = num1
    let num3:Int?? = 10
    print(num1 == num2)//true
    print(num1 == num3)//true
    print(num2 == num3)//true
}

img

func multipleOptional2(){
    let num1:Int? = nil
    let num2:Int?? = num1
    let num3:Int?? = nil
    print(num1 == num2)//true
    print(num1 == num3)//false
    print(num2 == num3)//false
}

img

可以使用lldb指令 frame variable –R 或者 fr v –R 查看区别

理解:如果两个多重可选项能解包出相同的盒子类型就是相等的可选项


行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.