Swift - 可选项(Optional)

文章目录

  • 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 += numindex += 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: Stringif let tmp = info["username"] {username = tmp}else {print("请输入用户名")return}var password: Stringif 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?? = 10print(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.mzph.cn/diannao/4614.shtml

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

相关文章

【论文阅读】互连网络的负载平衡路由算法 (CQR, Channel Queue Routing 通道队列路由)

Channel Queue Routing (CQR) 通道队列路由 1. Channel Queue Routing (CQR) 的动机 (1) 排队论(queueing theory)模型(2) GAL’s latency on tornado traffic(3) Routing tornado traffic with CQR 2. Channel Queue Routing 通道队列路由3. CQR 的性能4. 总结 Channel Queu…

白话机器学习1:分类问题中的评价指标

机器学习中的评价指标非常多&#xff0c;它们用来衡量模型的性能和预测能力。不同类型的机器学习任务可能需要不同的评价指标。以下是一些常见的评价指标&#xff0c;按照不同类型的机器学习任务分类&#xff1a; 对于分类问题&#xff1a; 准确率&#xff08;Accuracy&#…

[NeurIPS-23] GOHA: Generalizable One-shot 3D Neural Head Avatar

[pdf | proj | code] 本文提出一种基于单图的可驱动虚拟人像重建框架。基于3DMM给粗重建、驱动结果&#xff0c;基于神经辐射场给细粒度平滑结果。 方法 给定源图片I_s和目标图片I_t&#xff0c;希望生成图片I_o具有源图片ID和目标图片表情位姿。本文提出三个分支&#xff1a;…

pytorch中创建maskrcnn模型

0.模型输入/输出参数参见 链接: pytorch的mask-rcnn的模型参数解释 核心代码 GeneralizedRCNN(这里以mask-rcnn来解释说明) # 通过输入图像获取fpn特征图,注意这里的backbone不是直接的resnet,而是fpn化后的 features self.backbone(images.tensors) # 由于是mask-rcnn,故而…

SpringCloud系列(10)--Eureka集群原理及搭建

前言&#xff1a;当注册中心只有一个&#xff0c;而且当这个注册中心宕机了&#xff0c;就会导致整个服务环境不可用&#xff0c;所以我们需要搭建Eureka注册中心集群来实现负载均衡故障容错 Eureka架构原理图 1、Eureka集群原理 2、创建Eureka Server端服务注册中心模块 (1)在…

R语言使用sjPlot包优雅绘制回归模型的交互效应图

交互作用效应(p for Interaction)在SCI文章中可以算是一个必杀技&#xff0c;几乎在高分的SCI中必出现&#xff0c;因为把人群分为亚组后再进行统计可以增强文章结果的可靠性&#xff0c;进行可视化后可以清晰的表明变量之间的关系。不仅如此&#xff0c;交互作用还可以使用来进…

Dockerfile实战(SSH、Systemctl、Nginx、Tomcat)

目录 一、构建SSH镜像 1.1 dockerfile文件内容 1.2 生成镜像 1.3 启动容器并修改root密码 二、构建Systemctl镜像 2.1 编辑dockerfile文件 ​编辑2.2 生成镜像 2.3 启动容器&#xff0c;并挂载宿主机目录挂载到容器中&#xff0c;然后进行初始化 2.4 进入容器验证 三、…

照片误删怎么办?华为手机删除的照片如何恢复?

我们在使用华为手机时&#xff0c;可能会因为各种原因不小心删除一些照片。如果这些照片对我们来说很重要&#xff0c;那么恢复它们是非常必要且急迫的。那么华为手机删除的照片如何恢复呢&#xff1f;本文将为您介绍3种恢复华为手机中误删照片的方法。 如何恢复华为手机中被删…

Codeforces Round 941 (Div. 2)(A-D)

A. Card Exchange&#xff08;思维 Problem - A - Codeforces 题目大意&#xff1a; 给定n张牌&#xff0c;每次选k张相同的牌&#xff0c;把他们变成k-1张任意的牌&#xff0c;求最后手中最少能有几张牌。 思路&#xff1a; 直接判断这n张牌当中有没有k张一样的牌&#xff0c…

【java9】java9新特性之接口的私有方法

在Java 9中&#xff0c;接口可以包含私有方法&#xff08;包括静态私有方法和实例私有方法&#xff09;。这允许接口的设计者创建一些辅助方法&#xff0c;这些方法只能被接口中的其他方法所使用&#xff0c;而不能被实现该接口的类直接访问。 Java7 Java7及之前 &#xff0c…

软件项目管理的主要内容是什么?

目录 一、项目需求分析 二、项目计划制定 三、资源分配与调度 四、进度监控与控制 五、质量管理与保障 六、风险管理与应对 七、沟通协调与团队管理 八、项目收尾与总结 九、其他 一、项目需求分析 项目需求分析是软件项目管理的起始点&#xff0c;它涉及与客户的深入沟…

ubuntu22.04 修改内核源码教程

1. 确认当前内核版本 uname -a 2. 去ubuntu官网下载对应版本内核源码 6.5.0-28.29 : linux package : Ubuntu (launchpad.net) 3. 准备编译环境 sudo apt-get install libncurses5-dev libssl-dev build-essential openssl flex bison libelf-dev tar -xzvf linux_6.5.…

Spring Boot整合Redisson的两种方式

项目场景 Spring Boot整合Redisson的两种方式&#xff0c;方式一直接使用yml配置&#xff0c;方式二创建RedissonConfig配置类。 前言 redisson和redis区别&#xff1a; Redis是一个开源的内存数据库&#xff0c;支持多种数据类型&#xff0c;如字符串、哈希、列表、集合和有序…

Spring快速入门!(超详细)——工厂模式

GOF之工厂模式 设计模式&#xff1a;一种可以被重复利用的解决方案。GoF&#xff08;Gang of Four&#xff09;&#xff0c;中文名——四人组。《Design Patterns: Elements of Reusable Object-Oriented Software》&#xff08;即《设计模式》一书&#xff09;&#xff0c;19…

【网络安全】00后程序员,找 Bug 赚了 6,700,000元!他是怎么做到的?

1. 漏洞赏金计划&#xff08;Bug Bounty Programs&#xff09; 2. 安全咨询服务 3. 安全培训和教育 4. 写作和发表研究 5. 参与安全竞赛&#xff08;CTFs&#xff09; 6. 开发和销售安全工具 在网络安全领域&#xff0c;通过合法的方式利用漏洞赚钱主要涉及以下几种方法。…

【七十二】【算法分析与设计】64. 最小路径和,79. 单词搜索,1143. 最长公共子序列,利用记忆化递归填写dp表,可以很容易解决边界和填表顺序

递归填写dp表 利用递归函数填写dp表,可以很容易完成边界的处理,并且不用考虑填表的顺序. 绝大部分的动态规划可以用递归填表. 不用考虑填表顺序,只需要遍历一遍dfs即可. 64. 最小路径和 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路…

网络安全工程师必备的6个渗透测试工具

渗透测试是模拟黑客攻击&#xff0c;评估系统安全性的重要方法。 网络安全工程师需要掌握各种渗透测试工具&#xff0c;才能有效地发现和修复漏洞。 1. Nmap 功能: 强大的网络扫描器&#xff0c;可以扫描网络拓扑、识别主机和服务、发现开放端口和漏洞。 用途: 信息收集、漏洞…

Ubuntu编译安装MariaDB并进行初始化配置

Ubuntu编译安装MariaDB并进行初始化配置 1. 编译安装MariaDB2. 配置MariaDB3. Docker安装MariaDB 1. 编译安装MariaDB MariaDB官方安装文档&#xff1a;https://mariadb.com/kb/en/Build_Environment_Setup_for_Linux/    下载MariaDB源码&#xff1a;https://mariadb.org/ma…

Springboot + MySQL + html 实现文件的上传、存储、下载、删除

实现步骤及效果呈现如下&#xff1a; 1.创建数据库表&#xff1a; 表名&#xff1a;file_test 存储后的数据&#xff1a; 2.创建数据库表对应映射的实体类&#xff1a; import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.Table…

MySQL使用Sequence创建唯一主键

目录 第一章、快速了解Sequence1.1&#xff09;是什么&#xff1f;为什么使用1.2&#xff09;Sequence和自增主键的区别 第二章、在MySQL中使用Sequence2.1&#xff09;创建mysql_sequence表2.1.1&#xff09;创建表2.1.2&#xff09;插入数据 2.2&#xff09;创建函数2.2.1&am…