美文网首页
Swift: 06-可选项

Swift: 06-可选项

作者: DoBetter1 | 来源:发表于2023-03-07 22:21 被阅读0次
//可选项 Optional
//可选项,一般也叫可选类型,它允许将值设置为nil,默认不允许设置为nil
//在类型名称后面加个问号? 来定义一个可选项
var str: String? = "123"
str = nil

var age: Int? //可选值默认就是nil,var age:Int等价于var age:Int?= nil
age = 10
age = nil

var array = [1, 15, 40, 29]
func get(_ index:Int) -> Int? { //如果函数返回值可能为nil,返回值类型就要加?
    if index < 0 || index >= array.count {
        return nil
    } else {
        return array[index]
    }
}
print(get(1)) //Optional(15)
print(get(-1))//nil
print(get(4)) //nil

var age1:Int = 15
print(age1) //15

var age2:Int? = 15
print(age2) //Optional(15), 这个是可选类型


//强制解包(Forced Unwrapping)
//可选项是对其他类型的一层包装,可以将它理解为一个盒子
//如果为nil,那么它是个空盒子
//如果不为nil,那么盒子里面装的是:被包装类型的数据
var age3: Int? //默认就是nil
age3 = 10
age3 = nil

把10赋值给age3,如图相当于Int10这个蓝色的框框去掉
//如果要从可选项中取出被包装的数据(将盒子里面装的东西取出来),需要使用!进行强制解包
var age4: Int? = 10
var ageInt: Int = age4!
ageInt += 10

var age5: Int? = 10
var num = age5! + 20 //30
print(age5) //Optional(10)
//强制解包只是取值的过程,并不会修改age5本身的可选项值

//如果对值为nil的可选项(空盒子)进行强制解包,将会产生运行时错误,crash奔溃
//报错信息:Fatal error: Unexpectedly found nil while unwrapping an Optional value
var age6: Int?
//age6!  //这里会crash,报错先注释掉了

//判断可选项是否包含值
let number = Int("123")
if number != nil {
    print("字符串转换成功:\(number!)") //这里的number可能转换失败,返回0或者-1都不合适,只能返回nil,所以这种通过字符串转换成Int类型,number是可选类型,需要强制解包
} else {
    print("字符串转换整数失败,返回nil")
}
// 字符串转换整数成功:123
//var num = Int("xxx")


//可选项绑定
//可以使用可选项绑定来判断可选项是否包含值
//如果包含就自动解包,把值赋给一个临时的常量(let)或者变量(var),并返回true,否则返回false
if let number = Int("123") {
    print("字符串转换整数成功:\(number)")
    // number是强制解包之后的Int值
    // number作用域仅限于这个大括号
} else {
    print("字符串转换整数失败")
}

enum Season: Int {
    case spring = 1, summber, autumn, winter
}
//var sea = Season(rawValue: 2) 这里的sea是可选项,因为获取枚举传入原始值,可能不存在对应原始值的枚举变量
if let season = Season(rawValue: 6) { //这里需要注意,可选项绑定会帮忙自动解包,获取到的直接就是Season类型,而不是Season?可选类型
    switch season {
    case  .spring:
        print("the season is spring")
    default:
        print("the season is other")
    }
} else {
    print("no such season")
}
//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 {
    
}

//while循环中使用可选项绑定
//遍历数组,将遇到的正数都加起来,如果遇到负数或者非数字,停止遍历
var strs = ["10", "20", "30", "abc", "-20", "30"]
var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
    sum += num
    index += 1
}
print(sum) //60 10+20+30=60


//空合并运算符 ?? (Nil-Coalescing Operator)
//public func ?? <T>(optional:T?, defaultValue:@autoclosure () throws -> T?) rethrows -> T?
//
//public func ?? <T>(optional:T?, defaultValue:@autoclosure () throws -> T) rethrows -> T
//a ?? b
//1. 其中a必须是可选项,
//2. b是可选项 或者不是可选项
//3. b和a的存储类型必须相同
//4. 如果a 不为nil,就返回a
//5. 如果a 为nil,就返回b
//6. 如果b 不是可选项,返回a时自动解包

let a: Int? = 1
let b: Int? = 2
let c = a ?? b //1

let a1: Int? = nil
let b1: Int? = 2
let c1 = a1 ?? b1 //2

let a2: Int? = nil
let b2: Int? = nil
let c2 = a2 ?? b2 //nil

let a3: Int? = 1
let b3: Int = 2
let c3 = a3 ?? b3 //c是Int, 1

let a4: Int? = nil
let b4: Int = 2
let c4 = a4 ?? b4 //2

let a5: Int? = nil
let b5: Int = 2
//如果不使用?? 运算符
let c5: Int
if let tmp = a5 { //可选项会绑定失败
    c5 = tmp
} else {
    c5 = b5
}

//多个??一起使用
let a6: Int? = 1
let b6: Int? = 2
let c6 = a6 ?? b6 ?? 3 //c是Int,1

let a7: Int? = nil
let b7: Int? = 2
let c7 = a7 ?? b7 ?? 3 //c7是Int,2

let a8: Int? = nil
let b8: Int? = nil
let c8 = a8 ?? b8 ?? 3 //c8是Int,3

let a9: Int? = 1
let b9: Int? = 2
let c9 = a9 ?? 3 ?? b //c9是Int,这种会警告,??左边只能是可选项,不可以是Int

//??跟if let配合使用
let a10: Int? = nil
let b10: Int? = 2
if let c10 = a10 ?? b10{
    print(c10)
}
//类似于 if a != nil || b != nil, 并且可以自动解包赋值给 c10
//类似这种会有多个可选项解包可以使用多个 ?? 连接起来使用

if let c = a, let d = b {
    print(c)
    print(d)
}
//类似于 if a != nil && b != nil
//a自动解包成功并且b自动解包成功,if条件才满足,且的关系

//if 语句实现登陆
func login(_ info: [String: String]) {
    var username: String
    if let tmp = info["username"] {
        username = tmp
    } else {
        username = ""
        print("请输入用户名")
        return
    }
    
    var password: String
    if let tmp = info["password"] {
        password = tmp
    } else {
        password = ""
        print("请输入密码")
        return
    }
    //if username...
    //if password...
    print("用户名:\(username)","密码:\(password)","登陆ing")
}

login(["username":"jack","password":"123456"]) //用户名:jack 密码:123456 登陆ing
login(["password":"123456"]) //请输入用户名
login(["username":"jack"]) //请输入密码

//guard 语句
//当guard 语句的条件为false时,就会执行大括号里面的代码
//当guard 语句为true时,就会跳过guard语句
//guard语句特别适合用来 “提前退出”
func test() {
    guard 1>2 else {
        //do something
        //一定要推出当前作用域
        return
    }
}
//当使用guard语句进行可选项绑定时,绑定的常量(let),变量(var)也能在外层作用域中使用

//前面登陆的代码可以用guard来优化下:

func login2(_ info:[String:String]) {
    guard let username = info["username"] else {
        print("请输入用户名")
        return
    }
    guard let password = info["password"] else {
        print("请输入密码")
        return
    }
    //if username...
    //if password...
    print("用户名:\(username)","密码:\(password)","登陆ing")
}
login2(["username":"jack","password":"123456"]) //用户名:jack 密码:123456 登陆ing
login2(["password":"123456"]) //请输入用户名
login2(["username":"jack"]) //请输入密码


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

if let num3 = num1 {
    print(num3)
}

//尽量不要使用!,大多数情况下使用?的可选项
let num4:Int! = nil //加了!也是可选项,只不过是隐式解包的可选项
//let num5:Int = num4
//这里会报错:Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
//有一种情况,就是如果你希望别人传给你的参数必须是Int值,不能为nil,如果为nil,就崩溃掉,那就可以使用这种类型,这种也是不合理,还是期望使用?。


//字符串插值
//可选项在字符串插值或者直接打印时,编译器会发出警告
var age7: Int? = 10
print("my age is \(age7)") //my age is Optional(10)
//有三种方法可以消除警告
//1
print("my age is \(age7!)") //my age is 10
//2
print("my age is \(String(describing: age7))") //my age is Optional(10)
//3
print("my age is \(age7 ?? 0)") // my age is 10

//多重可选项
var num11: Int? = 10
var num22: Int?? = num11
var num33: Int?? = 10
print(num22 == num33) //true
image.png
var num111: Int? = nil
var num222: Int?? = num11
var num333: Int?? = nil

print(num222 == num333) //false
print(num111 == num333) //false

print((num222 ?? 1) ?? 2) //2
//这里(num222 ?? 1)强制解包之后是 num111,然后num111 ?? 2,因为num111 强制解包之后是nil,所以最终输入2
print((num333 ?? 1) ?? 2) //1
//这里 num333强值解包之后是nil,1 ?? 2,所以返回1
//可以使用lldb指令 frame variable -R 或者 fr v -R 查看区别
image.png
var num1: Int? = 10
var num2: Int?? = num1
var num3: Int?? = 10
image.png
var num1: Int? = nil
var num2: Int?? = num1
var num3: Int?? = nil
#这里有个注意点,如果num = 后面有值才是有意义的,如果是none是没有意义的
image.png

相关文章

网友评论

      本文标题:Swift: 06-可选项

      本文链接:https://www.haomeiwen.com/subject/nwtakdtx.html