目录

  • 1、nil
  • 2、可选绑定
  • 3、提供后备值
  • 4、强制解包
  • 5、隐式解包可选

在可能缺失值的情况下,请使用 可选。可选代表两种可能性:要么 存在一个指定类型的值,并可以解包可选以访问该值;要么 根本就没有值。

举一个可能缺失值的例子,Swift 的 Int 类型有一个初始化器,它会尝试将 String 值转换为 Int 值。但是,只有某些字符串可以转换成整数。字符串 "123" 可以转换成数值 123,但字符串 "hello, world"却没有对应的数值。下面的示例使用初始化器尝试将 String 转换为 Int

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber 的类型是 "可选 Int"。

因为上面代码中的初始化器可能会失败,所以它返回的是可选 Int,而不是 Int

要编写可选类型,需要在可选包含的类型名称后面加一个问号(?)。例如,可选 Int 的类型是 Int?。可选 Int 只能储存某个 Int 值或不储存任何值。它不能储存任何其他值,如 BoolString 值。

1、nil

通过给可选变量赋特殊值 nil,可以将其设置为无值状态:

var serverResponseCode: Int? = 404
// serverResponseCode 包含一个实际 Int 值 404
serverResponseCode = nil
// serverResponseCode 现在不包含任何值

如果你定义了一个可选变量,但没有提供默认值,那么该变量将自动设置为 nil

var surveyAnswer: String?
// surveyAnswer 自动设置为 nil

你可以使用 if 语句,通过比较可选和 nil 来确定可选是否包含一个值。你可以使用“等于”操作符(==)或“不等于”操作符(!=)进行比较。

如果可选有一个值,它就被视为“不等于” nil

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)if convertedNumber != nil {print("convertedNumber contains some integer value.")
}
// 打印 "convertedNumber contains some integer value."

不能在非可选常量或变量中使用 nil。如果代码中的常量或变量在某些条件下需要在没有值的情况下工作,请将其声明为适当类型的可选值。声明为非可选值的常量或变量保证永远不会包含 nil 值。如果尝试将 nil 赋值给一个非可选值,就会出现编译时错误。

通过将可选值和非可选值分开,可以显式标记哪些信息可能缺失,从而更方便编写处理缺失值的代码。你不能意外地将可选值当作非可选值来处理,因为这种错误会在编译时产生错误。在对值进行解包后,使用该值的其他代码都不需要检查 nil,因此不需要在代码的不同部分重复检查同一个值。

在访问可选值时,代码总是同时处理 nil 和非 nil 两种情况。当值缺失时,可以执行如以下各节所述的几项操作:

  • 当值为 nil 时,跳过对其进行操作的代码。
  • 通过返回 nil 或使用 doc:OptionalChaining 中记述的 ?. 运算符传播 nil 值。
  • 使用 ?? 运算符提供一个后备值。
  • 使用 ! 运算符停止程序执行。

备注: 在 Objective-C 中,nil 是指向不存在对象的指针。在 Swift 中,nil 并非指针,而是特定类型值的缺失。任何类型的可选都可以被设置为 nil,而不仅仅是对象类型。

2、可选绑定

你可以使用可选绑定来确定可选是否包含值,如果包含,则将该值作为临时常量或变量使用。可选绑定可与 ifguardwhile 语句一起使用,以检查可选中的值,并将该值提取到常量或变量中,作为单个操作的一部分。
使用 if 语句编写的可选绑定如下:

if let <#constantName#> = <#someOptional#> {<#statements#>
}
if let actualNumber = Int(possibleNumber) {print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {print("The string \"\(possibleNumber)\" couldn't be converted to an integer")
}
// 打印 "The string "123" has an integer value of 123"

该代码可理解为:

“如果 Int(possibleNumber) 返回的可选 Int 中包含一个值,则将它赋值给名为 actualNumber 的新常量。”

如果转换成功,actualNumber 常量就可以在 if 语句的第一个分支中使用。这个常量已经用可选中的值进行了初始化,并具有相应的非可选类型。在本例中,possibleNumber 的类型是 Int?,因此 actualNumber 的类型是 Int

如果在访问原可选常量或变量的值后不需要再引用它,则可以考虑使用相同的名称来命名新常量或变量:

let swift = Int(possibleNumber)
// 这里,myNumber 是一个可选整数
if let myNumber = myNumber {// 这里,myNumber 是一个非可选整数print("My number is \(myNumber)")
}
// 打印 "My number is 123"

这段代码首先检查 myNumber 是否包含一个值,就像上一个示例中的代码一样。如果 myNumber 有一个值,名为 myNumber 的新常量的值就会被设置为该值。在 if 语句的正文中,myNumber 指的就是这个新的非可选常量。在 if 语句之前或之后写 myNumber,指的是原来的可选整数常量。

由于这种代码非常常见,因此可以使用更简短的语法来解包可选值:只写常量或变量的名称即可。解包后的新常量或变量隐式地使用与可选值相同的名称。

if let myNumber {print("My number is \(myNumber)")
}
// 打印 "My number is 123"

你可以在可选绑定时使用常量或变量。如果你想在 if 语句的第一个分支中修改 myNumber 的值,你可以改写为 if var myNumber,这样,包含在可选中的值就可以作为变量而不是常量使用了。在 if 语句正文中对 myNumber 所做的修改仅适用于该局部变量,而不适用于原来的可选常量或变量。

你可以在一个 if 语句中包含任意数量的可选绑定和布尔条件,并用逗号分隔。如果可选绑定中的任何值为 nil,或任何布尔条件的值为 false,则整个 if 语句的条件被视为 false。以下 if 语句是等价的:

if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {print("\(firstNumber) < \(secondNumber) < 100")
}
// 打印 "4 < 42 < 100"if let firstNumber = Int("4") {if let secondNumber = Int("42") {if firstNumber < secondNumber && secondNumber < 100 {print("\(firstNumber) < \(secondNumber) < 100")}}
}
// 打印 "4 < 42 < 100"

if 语句中使用可选绑定创建的常量和变量只能在 if 语句的正文中使用。与此相反,用 guard 语句创建的常量和变量仅在 guard 语句后的代码行中可用,如 doc:ControlFlow#Early-Exit 中所述。

3、提供后备值

处理缺失值的另一种方法是使用 nil-coalescing 操作符(??)提供一个缺省值。如果 ?? 左边的可选值不是 nil,那么该值将被解包并使用。否则,将使用 ?? 右侧的值。例如,如果指定了姓名,下面的代码会用姓名问候某人,如果姓名为 nil,则使用通用问候语。

let name: String? = nil
let greeting = "Hello, " + (name ?? "friend") + "!"
print(greeting)
// 打印 "Hello, friend!"

4、强制解包

nil 表示不可恢复的故障时(如程序员错误或状态损坏),你可以通过在可选名称的末尾添加感叹号 (!) 来访问底层值。这被称为强制解包可选的值。强制解包一个非 nil 值时,结果是其解包值。强制解包一个 nil 值则会引发运行时错误。

实际上,!fatalError(_:file:line:) 的简写。例如,下面的代码显示了两种等效的方法:

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)let number = convertedNumber!guard let number = convertedNumber else {fatalError("The number was invalid")
}

上述两个版本的代码都要求于 convertedNumber 始终包含一个值。使用上述任一方法将该要求写入代码,可让代码在运行时检查该要求是否为真。

5、隐式解包可选

如上所述,可选表示允许常量或变量“无值”。可以用 if 语句检查可选值是否存在,如果可选值确实存在,则可以通过可选绑定有条件地解除对可选值的包裹。

有时,从程序结构中可以清楚地看出,在首次设置可选值后,该可选将始终有一个值。在这种情况下,无需在每次访问可选时都对其值进行检查和解包,因为你可以安全地假定它一直都有值。

这类可选被定义为隐式解包可选。在编写隐式解包可选时,需要在可选类型后面加上感叹号(String!)而不是问号(String?)。要注意不是在使用可选时在其名称后加上感叹号,而是在声明可选时在其类型后加上感叹号。

当首次定义可选后,可选的值立即被确认存在,并且可以确保在此后的每一个时间点都存在值时,隐式解包可选就非常有用了。

当变量有可能在稍后阶段变为 nil 时,不要使用隐式解包可选。如果需要在变量的生命周期内检查变量是否为 nil,请务必使用普通的可选类型。

隐式解包的可选在幕后是一个普通的可选值,但也可以像非可选值一样使用,而无需在每次访问时都进行解包。下面的示例显示了可选字符串和隐式解包的可选字符串在作为显式字符串访问其被包装值时的行为差异:

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要显式解包let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 隐式解包

你可以将隐式解包可选视为允许可选值在需要时被强制解包。在使用隐式解包的可选值时,Swift 会首先尝试将其作为普通可选值使用;如果不能将其作为可选值使用,Swift 就会强制解包该值。在上面的代码中,可选值 assumedString 在赋值给 implicitString 之前被强制解包,因为 implicitString 的类型是显式定义的非可选字符串。在下面的代码中,optionalString 没有显式类型,所以它是一个普通的可选值。

let optionalString = assumedString
// optionalString 的类型是 "String?",而 assumedString 没有强制解包。

如果一个隐式解包的可选值为 nil,而你试图访问它的被包装值,就会触发运行时错误。其结果与用感叹号来强制解包一个不包含值的普通可选完全相同。

你可以像检查普通可选一样,检查隐式解包的可选是否为 nil

if assumedString != nil {print(assumedString!)
}
// 打印 "An implicitly unwrapped optional string."

你也可以对隐式解包的可选使用可选绑定,在单个语句中检查并解包其值:

if let definiteString = assumedString {print(definiteString)
}
// 打印 "An implicitly unwrapped optional string."

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

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

相关文章

【数据结构】关于链表的面试题

一、单链表逆置1、法一思路&#xff1a;通过两个辅助指针 p和 q&#xff0c;在遍历链表时逐个反转指针方向。p初始化为 第一个有效节点&#xff0c;用于遍历原链表&#xff1b;q初始化为 NULL&#xff0c;用于临时保存 p 的下一个节点。plist->next 被置为 NULL&#xff0c;…

LVS(Linux virual server)

LVS&#xff08;Linux virual server&#xff09; 系统性能扩展方式 Scale UP&#xff1a;增强单台服务器性能&#xff0c;适合单体应用&#xff0c;但有硬件限制。 Scale Out&#xff1a;增加服务器数量&#xff0c;适合分布式和集群系统&#xff0c;可灵活扩展。 集群&#x…

在 ASP.NET Core 和 JavaScript 中配置 WebSocket

在本文中&#xff0c;我们将了解 WebSocket&#xff0c;并逐步讲解如何在客户端配置 WebSocket 并与服务器通信。首先&#xff0c;让我们先来了解一下“ WebSocket ”。什么是 WebSocketWebSocket 是一种协议&#xff0c;它提供了一种通过持久连接在客户端和服务器之间交换数据…

车载刷写框架 --- 关于私有节点刷写失败未报引起的反思

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

ABP VNext + GitHub Actions:CI/CD 全流程自动化

&#x1f31f; ABP VNext GitHub Actions&#xff1a;CI/CD 全流程自动化 &#x1f4da; 目录&#x1f31f; ABP VNext GitHub Actions&#xff1a;CI/CD 全流程自动化&#x1f929; TL;DR&#x1f504; 全局流程概览1️⃣ 准备工作与项目结构1.1 &#x1f6e0;️ 工具链与 S…

Elasticsearch 重命名索引

作者&#xff1a;来自 Elastic Alex Salgado 学习如何使用四种实用方法在 Elasticsearch 中重命名索引。 想获得 Elastic 认证&#xff1f;看看下一期 Elasticsearch Engineer 培训什么时候开始&#xff01; Elasticsearch 拥有丰富的新功能&#xff0c;帮助你根据使用场景构建…

高通8255 Android Virtio Virtio-SPI 配置方法

目录 一&#xff1a;VirtIO和Passthrough的区别 二&#xff1a;配置逻辑 三&#xff1a;配置方法 步骤一&#xff1a;QNX SPI资源配置 & 测试 配置 测试 步骤二&#xff1a;BE配置 &测试 配置 测试 步骤三&#xff1a;Hypervisor配置 配置 测试 步骤四&…

从零手写红黑树(C++实现详解)

目录 一、红黑树概述 二、红黑树节点设计 (1)枚举红黑 &#xff08;2&#xff09;红黑树的节点设计 三、红黑树核心实现:Insert 1.首先将节点遍历到对应位置创建对应节点并插入到二叉搜索树对应的位置 2.本文重点的重点 &#xff08;1&#xff09;parent为黑时直接插入即…

【黄山派-SF32LB52】—硬件原理图学习笔记

目录 一、硬件介绍 二、芯片主控 1.模组介绍 2.原理图介绍 3.模组供电电路 三、电源转换部分 1.OVP过压保护电路 2.CHG充电电路 3.系统电源桥接电路 4.LDO电路 四、Debug电路 1.一键下载电路 五、QSPI屏幕 六、SD卡 七、AUDIO音频 八、GPIO电路 1.按键部分…

从五次方程到计算机:数学抽象如何塑造现代计算

引言 数学的发展往往始于一个具体的问题&#xff0c;而后在寻求解答的过程中&#xff0c;催生出深刻的抽象理论。从五次方程的求解到抽象代数&#xff0c;再到范畴论和λ演算&#xff0c;最终影响图灵机和现代计算机的设计&#xff0c;这一历程展现了数学如何从实际问题演变为通…

剧本杀小程序开发:科技赋能,重塑推理娱乐新形态

在科技飞速发展的今天&#xff0c;各个行业都在积极探索与科技的融合&#xff0c;以实现创新发展。剧本杀行业也不例外&#xff0c;剧本杀小程序的开发&#xff0c;正是科技赋能传统娱乐的生动体现&#xff0c;它重塑了推理娱乐的新形态&#xff0c;为玩家带来了前所未有的游戏…

机器学习sklearn入门:归一化和标准化

bg&#xff1a;归一化&#xff08;Normalization&#xff09;通常指将数据按比例缩放至某个特定范围&#xff0c;但具体范围并不一定是固定的 0到1。标准化是将数据转换成均值为0&#xff0c;标准差为1的分布。使用场景&#xff1a;用归一化&#xff1a;需要严格限定范围&#…

【Project】kafka+flume+davinci广告点击实时分析系统

一、项目需求分析 某电商平台需实现广告实时点击分析系统&#xff0c;核心需求为实时统计以下内容的Top10&#xff1a; 各个广告的点击量各个省份的广告点击量各个城市的广告点击量 通过实时掌握广告投放效果&#xff0c;为广告投放策略调整和大规模投入提供依据&#xff0c;以…

JAVA后端开发——success(data) vs toAjax(rows): 何时用

toAjax(int rows)用途&#xff1a;用于不返回任何数据的 “写” 操作&#xff08;增、删、改&#xff09;。工作原理&#xff1a;它只接收一个 int 类型的参数&#xff08;通常是数据库操作影响的行数&#xff09;。它只关心这个数字是不是大于0&#xff0c;然后返回一个通用的…

pdf格式怎么提取其中一部分张页?

想从PDF里提取几个页面&#xff0c;办法还挺多的&#xff0c;下面给你唠唠常见的几种&#xff0c;保准你一看就懂。一、用专业PDF编辑软件提取 像Adobe Acrobat&#xff0c;这可是PDF编辑界的“老手”了。你先把要处理的PDF文件在Adobe Acrobat里打开&#xff0c;接着找到菜单栏…

Spring监听器

1、监听器的原理 ApplicationListener<T>是Spring框架中基于观察者模式实现的事件监听接口&#xff0c;用于监听应用程序中特定类型的事件。该接口是一个函数式接口&#xff0c;从Spring 4.2开始支持Lambda表达式实现。 接口定义如下&#xff1a; FunctionalInterface …

基于Rust游戏引擎实践(Game)

Rust游戏引擎推荐 以下是一些流行的Rust游戏引擎,适用于不同开发需求: Bevy 特点:数据驱动、模块化设计,支持ECS架构,适合初学者和复杂项目。 适用场景:2D/3D游戏、原型开发。 Amethyst 特点:成熟的ECS框架,支持多线程,社区活跃。 适用场景:大型游戏或高性能应用。…

PyTorch 数据加载实战:从 CSV 到图像的全流程解析

目录 一、PyTorch 数据加载的核心组件 1.1 Dataset 类的核心方法 1.2 DataLoader 的作用 二、加载 CSV 数据实战 2.1 自定义 CSV 数据集 2.2 使用 TensorDataset 快速加载 三、加载图像数据实战 3.1 自定义图像数据集 3.2 使用 ImageFolder 快速加载 四、加载官方数据…

程序人生,开启2025下半年

时光匆匆&#xff0c;2025年已然过去一半。转眼来到了7月份。 回望过去上半年&#xff0c;可能你也经历了职场的浮沉、生活的跌宕、家庭的变故。 而下半年&#xff0c;生活依旧充满了各种变数。 大环境的起起伏伏、生活节奏的加快&#xff0c;都让未来的不确定性愈发凸显。 在这…

在 .NET Core 中创建 Web Socket API

要在 ASP.NET Core 中创建 WebSocket API&#xff0c;您可以按照以下步骤操作&#xff1a;设置新的 ASP.NET Core 项目打开 Visual Studio 或您喜欢的 IDE。 创建一个新的 ASP.NET Core Web 应用程序项目。 选择API模板&#xff0c;因为这将成为您的 WebSocket API 的基础。在启…