当前位置: 首页 > news >正文

Swift6.0基础知识 -- 可选2

目录

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

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

举一个可能缺失值的例子,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 始终包含一个值。使用上述任一方法将该要求写入代码,可让代码在运行时检查该要求是否为真。

4、隐式解包可选

如上所述,可选表示允许常量或变量“无值”。可以用 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.dtcms.com/a/283223.html

相关文章:

  • 正则表达式梳理
  • Linux驱动13 --- 多节点设备树
  • MySQL主键策略解析:自增ID与UUID的优劣及选择建议
  • 7.17 滑动窗口 | assign
  • Docker容器访问挂载文件权限问题
  • MPPT电路设计
  • vue中后端返回数据流,前端实现导出下载
  • 等价关系与不变量
  • Web3:Solidity入门到精通
  • cdr序列化与反序列化
  • SenseGlove力反馈手套:医疗、生产制造、军事模拟与远程机器人控制新革命
  • 【AI交叉】化学:人工智能如何重塑现代化学研究?
  • 谷歌引入开源全栈 AI 代理栈:借助 Gemini 2.5 和 LangGraph 实现多步网络搜索、反思与综合
  • NMS代码详解(数据维度变换解析)
  • 格密码--Ring-SIS和Ring-LWE
  • 架构解密|一步步打造高可用的 JOCR OCR 识别服务
  • oracle会话控制和存储状态查询
  • pyqt当中splitter.setSizes()不生效
  • C++中vector和list的优缺点对比以及deque
  • PowerJob集群机器数为0问题
  • Python第八章作业(初级)
  • 如何使用VScode使用ssh连接远程服务器不需要输入密码直接登录
  • 27.Hamming 距离
  • transformers基础Data Collator
  • 教程:如何快速查询 A 股实时 K线和5档盘口
  • 今日行情明日机会——20250716
  • Redis深度解析:从缓存到分布式系统的核心引擎
  • 用python实现自动化布尔盲注
  • pytest--1--pytest-mock常用的方法
  • 代码随想录day36dp4