IOS Swift 从入门到精通: 可选项、展开和类型转换

文章目录

  • 处理缺失数据
  • 展开可选值
  • 用保护装置解开
  • 强制展开
  • 隐式解包可选值
  • 零合并
  • 可选链式调用
  • 可选尝试
  • 可失败的初始化器
  • 类型转换
  • 总结

处理缺失数据

我们已经使用诸如 之类的类型Int来保存像 5 这样的值。但是如果您想存储age用户的属性,如果您不知道某人的年龄,您会怎么做?

您可能会说“好吧,我会存储 0”,但这样一来,您就会混淆新生婴儿和您不知道年龄的人。您可以使用特殊数字(例如 1000 或 -1)来表示“未知”,这两个年龄都是不可能的,但您真的会记住所有使用这个数字的地方吗?

Swift 的解决方案称为可选类型,你可以用任意类型创建可选类型。可选整数可能包含数字 0 或 40,但它可能根本没有值 - 它可能真的缺失了,这是nilSwift 中的情况。

要使类型可选,请在其后添加问号。例如,我们可以像这样创建一个可选整数:

var age: Int? = nil

这并不代表任何数字——它什么也不代表。但如果我们后来知道了年龄,我们可以使用它:

age = 38

展开可选值

可选字符串可能包含像“Hello”这样的字符串,或者可能为零——什么都没有。

考虑这个可选字符串:

var name: String? = nil

如果我们使用会发生什么name.count?真正的字符串具有count存储其有多少个字母的属性,但这是nil– 它是空内存,而不是字符串,因此它没有count。

因此,尝试读取name.count是不安全的,Swift 不允许这样做。相反,我们必须查看可选值的内部并查看其中的内容 - 这个过程称为解包。

解包可选值的一种常见方法是使用if let语法,该语法使用条件进行解包。如果可选值中有一个值,那么您可以使用它,但如果没有,则条件不成立。

例如:

if let unwrapped = name {print("\(unwrapped.count) letters")
} else {print("Missing name.")
}

如果name包含字符串,它将被放入unwrapped常规中String,我们可以count在条件中读取其属性。或者,如果name为空,else则将运行代码。

用保护装置解开

的另一种方法if let是guard let,它也可以解开可选项。guard let将为您解开可选项,但如果它nil在里面找到它,它会期望您退出使用它的函数、循环或条件。

if let但是,和之间的主要区别guard let在于,解包的可选项在代码之后仍然可用guard。

让我们用一个函数来尝试一下greet()。它将接受一个可选字符串作为其唯一参数并尝试解包它,但如果里面没有任何内容,它将打印一条消息并退出。因为使用解包的可选值在完成guard let后仍然存在guard,所以我们可以在函数末尾打印解包的字符串:

func greet(_ name: String?) {guard let unwrapped = name else {print("You didn't provide a name!")return}print("Hello, \(unwrapped)!")
}

使用guard let可以让你在函数开始时处理问题,然后立即退出。这意味着函数的其余部分是快乐路径 - 如果一切正确,你的代码将采用该路径。

强制展开

可选值表示可能存在也可能不存在的数据,但有时您肯定知道某个值不为 nil。在这些情况下,Swift 允许您强制解包可选值:将其从可选类型转换为非可选类型。

例如,如果您有一个包含数字的字符串,则可以将其转换为Int如下形式:

let str = "5"
let num = Int(str)

这是num一个可选项 Int,因为您可能尝试转换像“Fish”而不是“5”这样的字符串。

尽管 Swift 不确定转换是否有效,但您可以看到代码是安全的,因此您可以通过!在之后写入来强制解开结果Int(str),如下所示:

let num = Int(str)!

Swift 会立即解开可选值并将其转换为num常规值Int,而不是Int?。但如果你错了——ifstr是无法转换为整数的东西——你的代码就会崩溃。

因此,只有当您确定它是安全的时候才应该强制解包 - 这就是它通常被称为崩溃操作员的原因。

隐式解包可选值

与常规可选项一样,隐式解包的可选项可能包含一个值,也可能是nil。但是,与常规可选项不同,您无需解包即可使用它们:您可以像使用它们根本不是可选项一样使用它们。

隐式解包的可选类型是通过在类型名称后添加感叹号来创建的,如下所示:

let age: Int! = nil

因为它们的行为就像已经解包一样,所以您不需要if let或guard let使用隐式解包的可选值。但是,如果您尝试使用它们并且它们没有值(如果有的话nil),您的代码就会崩溃。

隐式解包可选值之所以存在,是因为有时变量一开始为 nil,但在需要使用之前始终会有一个值。因为你知道在需要它们时它们会有一个值,所以不必一直写这个值会很有帮助if let。

话虽如此,如果您可以使用常规可选项,这通常是个好主意。

零合并

零合并运算符解包可选项并返回其中的值(如果有)。如果没有值(如果可选项有值nil),则使用默认值。无论哪种方式,结果都不是可选项:它要么是可选项内部的值,要么是用作备份的默认值。

这是一个接受整数作为其唯一参数并返回可选字符串的函数:

func username(for id: Int) -> String? {if id == 1 {return "Taylor Swift"} else {return nil}
}

如果我们使用 ID 15 调用该函数,我们会返回,nil因为无法识别该用户,但是使用 nil 合并,我们可以提供一个默认值"Anonymous",如下所示:

let user = username(for: 15) ?? "Anonymous"

这将检查从函数返回的结果username():如果它是一个字符串,那么它将被解开并放入user,但如果它有nil内部,那么将使用"Anonymous"

可选链式调用

Swift 为我们提供了使用可选变量的快捷方式:如果你想访问类似a.b.c和b可选的内容,你可以在它后面写一个问号以启用可选链接:a.b?.c。

当运行该代码时,Swift 将检查是否b有值,如果有,则nil该行的其余部分将被忽略 - Swift 将nil立即返回。但是如果它有值,它将被解包并继续执行。

为了尝试这一点,这里有一个名称数组:

let names = ["John", "Paul", "George", "Ringo"]

我们将使用该数组的属性,如果存在第一个名字或数组为空,first它将返回第一个名字。然后我们可以调用结果使其成为大写字符串:niluppercased()

let beatle = names.first?.uppercased()

那个问号是可选链接——如果first返回nil,那么 Swift 不会尝试将其大写,并且会立即设置beatle为nil。

可选尝试

当我们讨论抛出函数时,我们看了以下代码:

enum PasswordError: Error {case obvious
}func checkPassword(_ password: String) throws -> Bool {if password == "password" {throw PasswordError.obvious}return true
}do {try checkPassword("password")print("That password is good!")
} catch {print("You can't use that password.")
}

运行一个抛出函数,使用do、try和catch来优雅地处理错误。

有两种替代方法try,既然您现在理解了可选项和强制解包,那么这两种方法都会更有意义。

第一个是try?,并将抛出函数更改为返回可选值的函数。如果函数抛出错误,您将被发送nil结果,否则您将获得包装为可选值的返回值。

我们可以像这样try?运行:checkPassword()

if let result = try? checkPassword("password") {print("Result was \(result)")
} else {print("D'oh.")
}

另一种方法是try!,当您确信该函数不会失败时可以使用它。如果该函数确实抛出错误,您的代码将崩溃。

我们try!可以将代码重写如下:

try! checkPassword("sekrit")
print("OK!")

可失败的初始化器

当谈到强制展开时,我使用了以下代码:

let str = "5"
let num = Int(str)

这会将字符串转换为整数,但是因为您可能尝试传递任何字符串,所以您实际得到的是一个可选的整数。

这是一个可失败的初始化器:一个可能成功也可能失败的初始化器。您可以使用init?()而不是将这些初始化器写在您自己的结构和类中init(),如果出现错误则返回nil。返回值将是您类型的可选项,您可以随意解包。

例如,我们可以编写一个Person必须使用九个字母的 ID 字符串创建的结构。如果使用除九个字母字符串以外的任何其他字符串,我们将返回nil,否则我们将照常继续。

Swift 版本如下:

struct Person {var id: Stringinit?(id: String) {if id.count == 9 {self.id = id} else {return nil}}
}

类型转换

Swift 必须始终知道每个变量的类型,但有时你知道的信息比 Swift 知道的多。例如,这里有三个类:

class Animal { }
class Fish: Animal { }class Dog: Animal {func makeNoise() {print("Woof!")}
}

我们可以创建几条鱼和几条狗,并将它们放入一个数组中,如下所示:

let pets = [Fish(), Dog(), Fish(), Dog()]

Swift 可以看到Fish并Dog从类中继承Animal,因此它使用类型推断来创建pets一个数组Animal。

如果我们想要循环遍历pets数组并让所有的狗叫,我们需要执行类型转换:Swift 将检查每只宠物是否是一个Dog对象,如果是,那么我们就可以调用makeNoise()。

这使用了一个名为的新关键字as?,它返回一个可选项:nil如果类型转换失败则为,否则为转换后的类型。

以下是我们在 Swift 中编写循环的方法:

for pet in pets {if let dog = pet as? Dog {dog.makeNoise()}
}

总结

  • 可选项让我们能够以清晰明确的方式表示值的缺失。
  • Swift 不允许我们在未解包的情况下使用可选项,无论是使用if let还是使用guard let。
  • 您可以使用感叹号强制解开可选项,但如果您尝试强制解开,nil您的代码将会崩溃。
  • 隐式解包的可选项没有常规可选项的安全检查。
  • 您可以使用 nil 合并来解开可选项,如果其中没有任何内容,则提供默认值。
  • 可选链接让我们可以编写代码来操作可选项,但如果可选项为空,则代码将被忽略。
  • 您可以使用try?将抛出函数转换为可选的返回值,或者try!在抛出错误时崩溃。
  • 如果您需要您的初始化程序在输入错误输入时失败,请使用init?()可失败的初始化程序。
  • 您可以使用类型转换将一种类型的对象转换为另一种类型的对象。

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

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

相关文章

第8章:系统质量属性与架构评估

软件系统属性包括功能属性和质量属性,软件架构重点关注的是质量属性。架构的基本需求是在满足功能属性的前提下,关注软件系统质量属性。为了精确、定量地表达系统的质量属性,通常会采用质量属性场景的方式进行描述。   在确定软件系统架构&…

OpenGL3.3_C++_Windows(15)

理解glad: OpenGL只是一个标准/规范,具体的实现是由驱动开发商针对特定显卡实现的,由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询,因此开发者需要在运行时获取函数…

Flutter GetX 状态管理 响应式编程(三)

在2021年4月初,我们在应用开发中大量使用了 GetX,目前看来效果还不错,于是我最近也出了一套GetX的从入门到源码原理的分析教程,欢迎大家关注更新。 【1 GetX 基本使用路由管理】【2 GetX 使用入门 程序计数器】 第一步 使用 GetM…

可灵王炸更新,图生视频、视频续写,最长可达3分钟!Runway 不香了 ...

现在视频大模型有多卷? Runway 刚在6月17号 发布Gen3 ,坐上王座没几天; 可灵就在6月21日中午,重新夺回了王座!发布了图生视频功能,视频续写功能! 一张图概括: 二师兄和团队老师第一…

实施高效冷却技术:确保滚珠丝杆稳定运行!

滚珠丝杆在运行过程中,由于摩擦、惯性力等因素,会产生一定的热量,当热量无法及时散发时,滚珠丝杆的温度就会升高,会直接影响滚珠丝杆的精度和稳定性,从而影响最终的产品质量。为了让滚珠丝杆保持应有的精度…

Redis源码学习:ziplist的数据结构和连锁更新问题

ziplist ziplist 是 Redis 中一种紧凑型的列表结构&#xff0c;专门用来存储元素数量少且每个元素较小的数据。它是一个双端链表&#xff0c; 可以在任意一端进行压入/弹出操作&#xff0c;并且该操作的时间复杂度为O(1)。 ziplist数据结构 <zlbytes><zltail>&l…

Linux基础指令(三)

目录 shell 权限指令&#xff1a; 文件的操作权限&#xff1a; 对文件进行操作的用户分类&#xff1a; 用户对文件进行的操作分类&#xff1a; 所有者、所属组、其他的访问权限&#xff1a; 创建用户 沾滞位 匹配查找指令&#xff1a; grep find shell shell&#x…

Ubuntu22.04开机后发现IP地址变成127.0.0.1

开机就是这个样子 解决办法 ip地址可能被释放&#xff0c;需要重新设置成自动分配 sudo dhclient -v可能网卡未加托管 查看方式: nmcli n若是enable就是已被托管,若是disabled&#xff0c;说明网卡未被托管 解决办法: nmcli n on搞定

DataWhale - 吃瓜教程学习笔记(二)

学习视频&#xff1a;第3章-一元线性回归_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 3.1 - 3.2 一元线性回归 - 最小二乘法 - 极大似然估计 - 梯度 多元函数的一阶导数 - 海塞矩阵 多元函数的二阶导数 - 机器学习三要素

软件介绍—Fluent Reader (RSS阅读器)

软件介绍—Fluent Reader &#xff08;RSS阅读器&#xff09; 01 RSS介绍 RSS可翻译为简易信息聚合&#xff08;也叫聚合内容&#xff09;是一种基于XML的标准&#xff0c;在互联网上被广泛采用的内容包装和投递协议。简单来讲&#xff0c;就是可以“订阅”一些网站新发布的内…

【Android面试八股文】Kotlin内置标准函数also的原理是什么?

文章目录 原理解析应用场景为什么使用 `also`?also 是 Kotlin 标准库中的一个内置函数,其原理和应用场景可以通过源码和示例来解释。 原理解析 also 的定义如下: /*** Calls the specified function [block] with `this` value as its argument and returns `this` value.…

Android 开发Android Studio创建第一个Android应用

本文讲解如何Android Studio创建第一个Android应用。 启动Android Studio 或打开的项目的界面 点击File-New-New Project 选择“ Empty Views Activity”&#xff0c;点击Next 点击Next&#xff0c;项目创建完成如下&#xff1a; 创建项目完成&#xff0c;自带一个Activity。 …

FreeRTOS消息队列

队列简介 更详细的操作入下图所示&#xff1a; 传输数据的方法 FreeRTOS中的队列传输使用的是拷贝&#xff1a;把数据、把变量的值复制进队列里 FreeRTOS 使用拷贝值的方法&#xff0c;这更简单&#xff1a; &#xff08;1&#xff09; 局部变量的值可以发送到队列中&#…

linux最大线程数限制及打开最大文件数

1.root用户下执行 ulimit -a 然后查看 max user processes 这个值通常是系统最大线程数的一半 max user processes&#xff1a;当前用户同时打开的进程(包括线程)的最大个数为 2.普通用户下 ulimit -a 出现的max user processes的值 默认是 /etc/security/limits.d/20-nproc.co…

PHP环境搭建之使用PhpStudy

文章目录 1 PhpStudy1.1 简介1.2 下载&安装1.3 修改配置1.3.1 Apache配置1.3.2 MySQL配置1.3.3 MySQL启动问题 1.4 Composer1.4.1 简介1.4.2 下载安装1.4.3 修改配置1.4.4 使用命令 1 PhpStudy 1.1 简介 phpstudy是一个php运行环境的集成包&#xff0c;用户不需要去配置运…

深入解析Linux中的用户态与内核态

引言 在计算机科学中&#xff0c;为了保障系统安全和资源管理的有序性&#xff0c;操作系统引入了内核态和用户态的概念。这两种状态在权限、资源访问和系统控制方面存在显著差异&#xff0c;它们共同确保了操作系统的稳定性和安全性。 一、内核态与用户态的基本概念 内核态&…

KIVY BLOG Kivy tutorial 007: Introducing kv language

Kivy tutorial 007: Introducing kv language – Kivy Blog DECEMBER 18, 2019 BY ALEXANDER TAYLOR Kivy tutorial 007: Introducing kv language Kivy 导师课007&#xff1a; 介绍kv语言 Central themes: kv language, building a gui, integration with Python 中心主题:…

路由模式--哈希模式下使用a标签跳转会有问题

路由模式分为 history 和 hash 两种模式&#xff0c;在 hash 模式下&#xff0c;使用 a 标签去跳转路由&#xff0c;可能会有问题。 比如&#xff1a; <a href"/home"><img src"/logo.png" class"logo" /></a> 在跳转路由时…

切面aspect处理fegin调用转本地调用

切面处理fegin调用转本地调用 问题:原fegin调用转本地调用详细描述方案代码实现总结问题:原fegin调用转本地调用 项目原来是微服务项目服务与服务之间是通过fegin进行交互的,但是现在微服务项目要重构为单体项目,原fegin调用的方法要给为本地调用 详细描述 zyy-aiot │ …

神经网络学习6-线性层

归一化用的较少 正则化用来解决过拟合&#xff0c;处理最优化问题&#xff0c;批量归一化加快速度 正则化&#xff08;Regularization&#xff09;&#xff1a; 作用&#xff1a;正则化是一种用来防止过拟合的技术&#xff0c;通过向模型的损失函数中添加惩罚项&#xff0c;使…