Swift - 可选项(Optional)

news2024/10/6 16:28:07

文章目录

  • Swift - 可选项(Optional)
    • 1. 可选项(Optional)
    • 2. 强制解包(Forced Unwrapping)
    • 3. 判断可选项是否包含值
    • 4. 可选项绑定(Optional Binding)
    • 5. 等价写法
    • 6. while循环中使用可选项绑定
    • 7. 空合并运算符 ??(Nil-Coalescing Operator)
      • 7.1 API
      • 7.2 示例
    • 8. 多个??一起使用
    • ??跟if let配合使用
    • if语句实现登陆
    • guard语句
    • 9. 隐式解包(Implicitly Unwrapped Optional)
    • 10. 字符串插值
    • 11. 多重可选项

Swift - 可选项(Optional)

1. 可选项(Optional)

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

无法赋值为nil

使用?

没设置初始值时,默认是nil

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

函数可以返回nil

var array = [1, 15, 40 , 29]
func get(_ index: Int) -> Int? {
    if index < 0 || index >= array.count {
        return nil
    }
    return array[index]
}
print(get(1))  // Optional(15)
print(get(-1))  // nil
print(get(4))  // nil

通过打印结果可以看出是否是可选类型

var age: Int = 15
print(age)

var age1: Int? = 15
print(age1)

2. 强制解包(Forced Unwrapping)

可选项是对其他类型的一层包装,可以将它理解为一个盒子

如果为nil,那么它是个空盒子

如果不为nil,那么盒子里装的是:被包装类型的数据

拿这个例子来说:

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

var age: Int?相当于是空盒子

age = 10相当于把数据装到盒子里去

age = nil相当于把数据从盒子里面拿掉

如果要从可选项取出被包装的数据(将盒子里装的东西取出来),需要使用感叹号 ! 进行强制解包

var age: Int? = 10
let ageInt: Int = age!
print(age)  // Optional(10)
print(ageInt)  // 10

解包后打印结果就不是Optional

如果对值为nil的可选项(空盒子)进行强制解包,将会产生运行时错误

3. 判断可选项是否包含值

我们可以先判断可选项是否包含值,再进行强制解包

let number = Int("123")
if number != nil {
print("字符串转换整数成功:\(number!)")
} else {
print("字符串转换整数失败")
}
// 字符串转换整数成功:123

4. 可选项绑定(Optional Binding)

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

简单用法

if let number = Int("123") {
    print("字符串转整数成功:\(number)")
    // number是强制解包后的Int值
    // number的作用域仅限这个大括号内
}
else {
    print("字符串转整数失败")
}
// 字符串转整数成功:123

季节 示例

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("th season is other")
    }
} else {
    print("no such season")
}
// no such season

5. 等价写法

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

等价于:

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

6. 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)

7. 空合并运算符 ??(Nil-Coalescing Operator)

7.1 API

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

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

7.2 示例

a ?? b

  • a 是可选项
  • b 是可选项 或者 不是可选项
  • b 跟 a 的存储类型必须相同

如果 a 不为nil,就返回 a

如果 anil,就返回 b

如果 b 不是可选项,返回 a 时会自动解包


a、b都是可选项

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

a不为nil,所以cInt?Optional(1)

a是nil,b是可选项

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

anil,返回b,所以cInt?Optional(2)

ab都是nil

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

anil,返回bb也是nil,所以cInt?nil

a是可选项,b不是可选项

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

a不为nil,返回a,但是因为b不是可选项,返回a时会自动解包,所以cInt1

anilb不是可选项

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

anil,返回bbInt,所以cInt2

如果不使用??运算符

let a: Int? = nil
let b: Int = 2
let c: Int
if let tmp = a {
    c = tmp
}
else {
    c = b
}
// c = 2

8. 多个??一起使用

a、b都是可选项

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

a不为nil,返回a,得到 => a ?? 3,3Int,所以cInt3

a为nil、b都可选项

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

anil,返回b,得到 => b ?? 3,b不为nil,返回b3Int,所以cInt3

a、b都为nil

let a: Int? = nil
let b: Int? = nil
let c = a ?? b ?? 3

anil,返回b,得到 => b ?? 3,bnil,返回3,所以cInt3

??跟if let配合使用

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

类似于if a != nil && b != nil

if语句实现登陆

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

guard语句

语法

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

使用guard语句改造上面登录代码

func login(_ 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")
}
login(["username" : "jack", "password" : "123456"])  // 用户名:jack 密码:123456 登录ing
login(["username" : "jack"])  // 请输入密码

9. 隐式解包(Implicitly Unwrapped Optional)

  • 在某些情况下,可选项一旦被设定值之后,就会一直拥有值
  • 在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值
  • 可以在类型后面加个感叹号 ! 定义一个隐式解包的可选项

前面我们使用如下方式进行强制解包

let num1: Int? = 10
let num2: Int = num1!

这种方式在每次使用的时候,需要使用!来强制解包

我们可以在可选项类型后面加个感叹号 !,是其成为一个隐式解包的可选项,在后续使用过程中它将会自动解包

let num1: Int! = 10
let num2: Int = num1

如果隐式解包nil解包时会报错

我们可以对其进行判空处理

if num1 != nil {
    print(num1 + 6)  // 16
}
if let num3 = num1 {
    print(num3)  // 10
}

10. 字符串插值

可选项在字符串插值或者直接打印时,编译器会发出警告

至少有3种方法消除警告
强制解包:

print("my age is \(age!)")  // my age is 10

使用Stringdescribing

print("my age is \(String(describing: age))")  // my age is Optional(10)

空合并运算符??

print("my age is \(age ?? 0)")  // my age is 10

11. 多重可选项

多重可选项,相当于装了多层盒子

var num1: Int? = 10
var num2: Int?? = num1
var num3: Int?? = 10

print(num2 == num3) // true


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

fr v -R num1
fr v -R num2
fr v -R num3


num1、num3为nil的情况

var num1: Int? = nil
var num2: Int?? = num1
var num3: Int?? = nil

fr v -R num1
fr v -R num2
fr v -R num3

@oubijiexi

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1638039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【linuxC语言】stat函数

文章目录 前言一、stat函数二、示例代码总结 前言 在Linux系统编程中&#xff0c;stat() 函数是一个非常重要的工具&#xff0c;用于获取文件的元数据信息。无论是在系统管理、文件处理还是应用开发中&#xff0c;都可能会用到 stat() 函数。通过调用 stat() 函数&#xff0c;…

简约大气的全屏背景壁纸导航网源码(免费)

简约大气的全屏背景壁纸导航网模板 效果图部分代码领取源码下期更新预报 效果图 部分代码 <!DOCTYPE html> <html lang"zh-CN"> <!--版权归孤独 --> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible…

用LM Studio搭建微软的PHI3小型语言模型

什么是 Microsoft Phi-3 小语言模型&#xff1f; 微软Phi-3 模型是目前功能最强大、最具成本效益的小型语言模型 &#xff08;SLM&#xff09;&#xff0c;在各种语言、推理、编码和数学基准测试中优于相同大小和更高大小的模型。此版本扩展了客户高质量模型的选择范围&#x…

C# Winform父窗体打开新的子窗体前,关闭其他子窗体

随着Winform项目越来越多&#xff0c;界面上显示的窗体越来越多&#xff0c;窗体管理变得更加繁琐。有时候我们要打开新窗体&#xff0c;然后关闭多余的其他窗体&#xff0c;这个时候如果一个一个去关闭就会变得很麻烦&#xff0c;而且可能还会出现遗漏的情况。这篇文章介绍了三…

Stylus深度解析:开发效率提升秘籍(AI写作)

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

基于北京迅为iTOP-RK3588大语言模型部署测试

人工智能&#xff08;AI&#xff09;领域中的大模型&#xff08;Large Model&#xff09;逐渐成为研究的热点。大模型&#xff0c;顾名思义&#xff0c;是指拥有海量参数和高度复杂结构的深度学习模型。它的出现&#xff0c;不仅推动了AI技术的突破&#xff0c;更为各行各业带来…

社交媒体数据恢复:Sugram

Sugram数据恢复的方法 在本文中&#xff0c;我们将探讨Sugram数据恢复的基本方法。通过专业软件按照数据恢复步骤来了解如何进行数据恢复。 1. 立即停止使用设备 一旦发现数据丢失&#xff0c;第一步应该是立即停止使用该设备。这是因为每次设备被使用&#xff0c;都有可能导…

SpringBoot~ dubbo + zookeeper实现分布式开发的应用

配置服务名字, 注册中心地址, 扫描被注册的包 server.port8081 #当前应用名字 dubbo.application.nameprovider-server #注册中心地址 dubbo.registry.addresszookeeper://127.0.0.1:2181 #扫描指定包下服务 dubbo.scan.base-packagescom.demo.service 实现一个接口,在…

IoTDB 入门教程③——基于Linux系统快速安装启动和上手

文章目录 一、前文二、下载三、解压四、上传五、启动六、执行七、停止八、参考 一、前文 IoTDB入门教程——导读 二、下载 下载二进制可运行程序&#xff1a;https://dlcdn.apache.org/iotdb/1.3.1/apache-iotdb-1.3.1-all-bin.zip 历史版本下载&#xff1a;https://archive.…

ROS2专栏(三) | 理解ROS2的动作

​ 1. 创建一个动作 目标&#xff1a; 在ROS 2软件包中定义一个动作。 1.1 新建包 设置一个 workspace 并创建一个名为 action_tutorials_interfaces 的包&#xff1a; mkdir -p ros2_ws/src #you can reuse existing workspace with this naming convention cd ros2_ws/s…

STM32 工程移植 LVGL:一步一步完成

STM32 工程移植 LVGL&#xff1a;一步一步完成 LVGL&#xff0c;作为一款强大且灵活的开源图形库&#xff0c;专为嵌入式系统GUI设计而生&#xff0c;极大地简化了开发者在创建美观用户界面时的工作。作为一名初学者&#xff0c;小编正逐步深入探索LVGL的奥秘&#xff0c;并决…

52.HarmonyOS鸿蒙系统 App(ArkTS)配置文件添加多个权限方法

52.HarmonyOS鸿蒙系统 App(ArkTS)配置文件添加多个权限方法 module.json5

关于修改hosts,浏览器并没有刷新生效的问题.

1.windows系统用cmd命令: ipconfig /flushdns 进行刷新.并查看本地解析是否已经刷新. 2.检查是否开了,代理,代理还是有影响的,关闭,不然不会生效 3.针对谷歌浏览器解决方案: 访问: chrome://net-internals/?#sockets 点击close idle sockets和flush socket pools,,,清…

如何将安卓手机投屏到Windows 10电脑上

诸神缄默不语-个人CSDN博文目录 我之所以要干这个事是为了用手机直播的时候在电脑上看弹幕…… 文章目录 1. 方法一&#xff1a;直接用Win10内置的投影到此电脑2. 方法二&#xff1a;用AirDroid Cast投屏到电脑上 1. 方法一&#xff1a;直接用Win10内置的投影到此电脑 在设置…

Flutter笔记:Widgets Easier组件库(8)使用图片

Flutter笔记 Widgets Easier组件库&#xff08;8&#xff09;&#xff1a;使用图片 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…

小程序wx.getlocation接口如何开通?

小程序地理位置接口有什么功能&#xff1f; 随着小程序生态的发展&#xff0c;越来越多的小程序开发者会通过官方提供的自带接口来给用户提供便捷的服务。但是当涉及到地理位置接口时&#xff0c;却经常遇到申请驳回的问题&#xff0c;反复修改也无法通过&#xff0c;给的理由…

Microsoft.NET 框架程序设计 —— 共享程序集

文件版本是一个很难解决的问题。实际上,如果仅仅在一个文件中将其某一位从0改变到1、或者从1改变到0,我们便不能绝对保证使用原来文件的代码和它使用新版文件时的行为一样。这是因为许多应用程序都会有意或者无意地引入bug。如果一个文件的后续版本修复了一个bug,应用程序便…

PotatoPie 4.0 实验教程(34) —— FPGA实现摄像头图像二值化腐蚀效果

链接直达 https://item.taobao.com/item.htm?ftt&id776516984361 图像二值化腐蚀处理有什么作用&#xff1f; 图像二值化腐蚀处理在图像处理中起到了以下作用&#xff1a; 物体分割与提取&#xff1a;在图像二值化之后&#xff0c;通过腐蚀操作可以消除噪声、连接相邻的…

搭建Kafka源码环境并测试

文章目录 一、前言二、环境准备三、环境搭建3.1 JDK 环境搭建3.2 Scala 环境搭建3.2.1 配置 Scala 环境变量3.2.2 验证 3.3 Gradle 环境搭建3.3.1 配置 Gradle 环境变量3.3.2 验证 3.4 Zookeeper 环境搭建3.4.1 配置 Zookeeper 环境变量3.4.2 验证 3.5 Kafka 源码搭建3.5.1 导入…

44. UE5 RPG 初始化敌人的属性

在正常的游戏中&#xff0c;我们应该考虑如何去初始化角色属性&#xff0c;并且要给角色分好类型。比如&#xff0c;在我们游戏中&#xff0c;我们如何去初始化小兵的属性&#xff0c;并且还要实现小兵随着等级的增长而增加属性。而且就是小兵也有类型的区分&#xff0c;比如我…