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

2024-06-22 20:52

本文主要是介绍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?()可失败的初始化程序。
  • 您可以使用类型转换将一种类型的对象转换为另一种类型的对象。

这篇关于IOS Swift 从入门到精通: 可选项、展开和类型转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085390

相关文章

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三

从入门到精通详解LangChain加载HTML内容的全攻略

《从入门到精通详解LangChain加载HTML内容的全攻略》这篇文章主要为大家详细介绍了如何用LangChain优雅地处理HTML内容,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录引言:当大语言模型遇见html一、HTML加载器为什么需要专门的HTML加载器核心加载器对比表二

从入门到进阶讲解Python自动化Playwright实战指南

《从入门到进阶讲解Python自动化Playwright实战指南》Playwright是针对Python语言的纯自动化工具,它可以通过单个API自动执行Chromium,Firefox和WebKit... 目录Playwright 简介核心优势安装步骤观点与案例结合Playwright 核心功能从零开始学习

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指