Skip to content

第1天 变量、常量、字符串和数字

SwiftUI 是一个强大的框架,用于为 iOS、macOS、tvOS 甚至 watchOS 构建用户交互应用。但没有编程语言就无法开发软件,所以 SwiftUI 的背后是 Swift 本身:这是一种强大、灵活且现代化的编程语言,你将在所有 SwiftUI 应用中使用它。

正如马克・吐温曾经说过的:“取得进步的秘诀在于开始行动。” 好吧,你现在就要开始了,所以我们将深入学习 Swift 中的变量、常量和简单数据类型。

今天你需要完成七个教程。 如果你想更深入地了解每个主题,有一些可选的扩展阅读,但除非你愿意且有时间,否则不需要阅读。无论如何,有一些简短的测试可以帮助确保你理解了关键概念。

我知道,我知道:你很想继续观看更多视频并参加除下面链接之外的更多测试,但请记住:不要急于求成!每天学习一小时,坚持下去,比断断续续地学一大块要好得多。

1.1 为什么选择 Swift?

作者:Paul Hudson 2021 年 10 月 1 日 已针对 Xcode 16.4 更新

世界上有很多编程语言,但我相信你会非常喜欢学习 Swift。部分原因是出于实际考虑 —— 你可以在 App Store 上赚很多钱!—— 但也有很多技术层面的原因。

你要知道,Swift 是一种相对较新的语言,2014 年才推出。这意味着它没有许多古老语言所存在的冗余代码问题,而且通常情况下,解决某个特定问题只有一种方法。

同时,作为一种如此新的编程语言,Swift 借鉴了各种基于旧语言成功经验(有时也包含错误)的新理念。例如,它降低了意外编写不安全代码的可能性,让编写清晰易懂的代码变得非常容易,并且它支持世界上所有语言,所以你永远不会遇到其他语言中常见的那些奇怪的字符错误。

Swift 本身只是一门语言,并非为在屏幕上绘制内容而设计。当涉及到用 Swift 开发软件时,你会用到 SwiftUI:苹果的强大框架,它可以创建文本、按钮、图像、用户交互等等。顾名思义,SwiftUI 是为 Swift 量身打造的 —— 它确实充分利用了该语言所提供的强大功能和安全性,这使得构建真正强大的应用程序变得异常快捷。

所以,你应该学习 Swift,因为你可以用它赚很多钱,还因为它在很多方面都表现出色。没有冗余,没有困惑,只有强大的功能任你掌控。还有什么不喜欢的呢?

1.2 关于本课程

作者:Paul Hudson 2021 年 10 月 1 日 已更新至 Xcode 16.4 版本

自 2014 年 Swift 语言推出以来,我就一直在教人们编写 Swift 代码。到目前为止,Hacking with Swift 已经成为全球最大的专注于教授 Swift 的网站。

在这个过程中,我学到了很多东西:哪些主题最为重要,如何将这些主题组织成流畅且连贯的学习流程,而最重要的是,如何帮助学习者记住他们所学的内容。本课程就是所有这些经验的成果。

与我之前的作品不同,本课程并不试图教你 Swift 的方方面面,而是将更多时间花在那些最为重要的功能子集上 —— 就是那些你在构建每个应用时都会反复用到的功能。当然,课程中也涵盖了一些高级语言特性,但这些都是我根据其实用性精心挑选的。当你学完这本书后,可能会想继续学习一些更高级的特性,但我猜你更愿意忙着学习如何使用 SwiftUI。

本书的每一章都有文字和视频两种形式,但它们涵盖的内容完全相同,所以你可以选择最适合自己的学习方式。如果你观看视频,会发现我有时会用幻灯片介绍主题,有时会在 Xcode 中进行演示。这可能会让人觉得有些重复,但这是有意为之 —— 有很多内容需要学习,而如果每个内容你只看一次,是很难记住的!

最后还有一点:你可能会注意到很多章节都以 “如何……” 开头,这也是有意安排的 —— 这本书旨在以实践的方式向你展示如何做事,而不是深入探讨理论。理论固然重要,在你继续学习的过程中会遇到很多理论知识,但在这里,重点始终是实用性,因为我相信学习新事物的最佳方式是亲自尝试。

编程是一门艺术:不该在本该画画的时候,把所有时间都花在削铅笔上。

1.3 如何跟上学习进度

作者:Paul Hudson 2023 年 9 月 22 日 已针对 Xcode 16.4 更新

这本书中展示了大量代码,我非常鼓励你亲自尝试所有代码 —— 把代码输入到你的电脑中,运行它并查看输出结果,然后进行一些实验以确保你理解了代码。

要运行本书中的代码,你需要从 Mac App Store 安装 Xcode 15.0 或更高版本。它是免费的,包含你跟上学习进度所需的一切。

我们将使用 Swift Playground 来运行本书中的所有代码。你可以通过启动 Xcode,然后进入 “文件” 菜单并选择 “新建”>“Playground” 来创建一个。当被问及要创建哪种类型的 Playground 时,从 macOS 选项卡中选择 “空白”,然后将其保存到你容易找到的地方。

Playground 就像小小的沙盒,你可以在其中轻松尝试 Swift 代码,在代码旁边就能看到工作成果。你可以使用一个 Playground 来完成所有工作,也可以为每一章创建一个新的 Playground—— 做任何对你来说最有效的事情。

提示: 第一次在 Playground 中运行代码可能需要几秒钟才能启动,但后续运行会很快。

1.4 如何创建变量和常量

作者:Paul Hudson 2021 年 10 月 1 日 已针对 Xcode 16.4 更新

在编写程序时,你总会需要存储一些数据。可能是用户刚刚输入的姓名,可能是从互联网上下载的一些新闻报道,也可能是你刚刚完成的复杂计算的结果。

Swift 提供了两种存储数据的方式,具体取决于您是否希望数据随时间变化。创建新的 Playground 时会自动使用第一种方式,因为它包含以下代码:

swift
var greeting = "Hello, playground"

这行代码创建了一个名为 greeting 的变量,由于它是变量,其值可以变化—— 在程序运行过程中可以被修改。

提示: macOS playground 中的另一行代码是 import Cocoa,它引入了苹果提供的大量代码集合,以便更轻松地构建应用程序。这其中包含了许多重要功能,所以请不要删除它。

这行代码中实际上包含四个语法部分:

  • var 关键字表示 “创建一个新变量”,这样可以节省一些输入。
  • 我们将变量命名为 greeting。你可以给变量起任何名字,但大多数时候你会希望名字具有描述性。
  • 等号用于给变量赋值。你也可以不在等号两边加空格,但这是最常见的写法。
  • 我们赋予的值是文本 “Hello, playground”。注意,文本是写在双引号内的,这样 Swift 就能知道文本的开始和结束位置。

如果你使用过其他语言,可能会注意到我们的代码行末尾不需要分号。Swift允许使用分号,但这种情况非常少见 —— 只有当你出于某种原因想在同一行写两段代码时才需要用到。

创建变量后,你可以随时修改它的值:

swift
var name = "Ted"
name = "Rebecca"
name = "Keeley"

这段代码创建了一个名为 name 的新变量,并给它赋值为 “Ted”。然后它被修改了两次,首先改为 “Rebecca”,接着改为 “Keeley”—— 这里没有再次使用 var,因为我们是在修改已有的变量,而不是创建新变量。你可以根据需要多次修改变量,每次修改时旧值都会被丢弃。(你当然可以在变量中放入不同的文本,但我是电视剧《足球教练》的忠实粉丝,所以就用了 Ted 这个名字。而且可以预见,在接下来的章节中还会有其他《足球教练》的引用等等。)

如果你不希望某个值被改变,就需要使用常量。创建常量的方式几乎和创建变量一样,只是我们用 let 而不是 var,如下所示:

swift
let character = "Daphne"

使用 let 创建的是常量,其值不能被改变。Swift 绝对不允许修改常量的值,如果尝试修改,会显示一个明显的错误。

不相信吗?试着在 Xcode 中输入这段代码:

swift
let character = "Daphne"
character = "Eloise"
character = "Francesca"

同样,第二行和第三行中没有 let 关键字,因为我们不是在创建新的常量,只是试图修改已有的那个。但是,就像我说的,这行不通 —— 你不能修改常量,否则它就不叫常量了!

如果你好奇的话,“let” 来源于数学领域,在数学中人们会说 “令 x 等于 5” 之类的话。

重要提示: 请删除显示错误的那两行代码 —— 你确实不能修改常量!

学习 Swift 时,你可以让 Xcode 打印出任何变量的值。在实际应用中你不会经常用到这个功能,因为用户看不到打印的内容,但作为一种查看数据内部情况的简单方法,它非常有用。

例如,我们可以在每次设置变量值时打印出来 —— 试着在你的 playground 中输入这段代码:

swift
var playerName = "Roy"
print(playerName)

playerName = "Dani"
print(playerName)

playerName = "Sam"
print(playerName)

提示: 你可以通过点击代码左侧的蓝色播放图标来运行 Xcode playground 中的代码。如果你沿着蓝色条上下移动,会发现播放图标也会跟着移动 —— 这让你可以运行到某个特定点的代码,但在这里大多数时候你会想运行到最后一行。

你可能已经注意到,我把变量命名为 playerName,而不是 playernameplayer_name 或其他形式。这是一种选择:Swift 并不真正关心你的常量和变量叫什么名字,只要你在所有地方都用相同的方式引用它们就行。所以,我不能先使用 playerName,然后再用 playername——Swift 会认为这两个是不同的名字。

虽然 Swift 不关心我们如何给数据命名,但我使用的命名风格是 Swift 开发者中的标准 —— 我们称之为约定。如果你好奇的话,这种风格叫做 “驼峰式命名法”,因为名称中第二个及以后的单词以大写字母开头,就像小驼峰一样:

swift
let managerName = "Michael Scott"
let dogBreed = "Samoyed"
let meaningOfLife = "How many roads must a man walk down?"

如果可以的话,尽量使用常量而不是变量 —— 这不仅能让 Swift 有机会对代码进行一些优化,还能让 Swift 确保你不会意外地修改常量的值。

【可选阅读】为什么 Swift 有变量?

作者:Paul Hudson 2021 年 10 月 25 日 已针对 Xcode 16.4 更新

变量允许我们在程序中存储临时信息,并且是几乎每个 Swift 程序的关键组成部分。归根结底,你的程序总会以某种方式处理数据:或许是让用户输入待办事项然后勾选完成,或许是让他们在荒岛上闲逛为贪婪的浣熊干活,又或者是读取设备时间并在时钟上显示。不管怎样,你都是在获取某种数据,对其进行某种处理,然后展示给用户。

当然,“以某种方式处理数据” 才是真正的魔力所在,因为这正是你绝妙的应用创意得以实现的部分。但在内存中存储数据 —— 比如保存用户输入的内容,或者从互联网上下载的东西 —— 就需要用到变量了。

一旦使用 var 创建了一个变量,你就可以随时更改它的值,而无需再次使用 var。例如:

swift
var favoriteShow = "女子监狱"
favoriteShow = "善地"
favoriteShow = "神秘博士"

如果有帮助的话,你可以把 var 理解为 “创建一个新变量”。所以,上面第一行代码大声读出来可能是 “创建一个名为 favoriteShow 的新变量,并给它赋值为《女子监狱》”。第二行和第三行没有 var,所以它们是修改已有变量的值,而不是创建新变量。

现在试想一下,如果三行都加上 var—— 每次都写 var favoriteShow。这就没什么意义了,因为你相当于在说 “创建一个名为 favoriteShow 的新变量” 三次,而第一次创建之后,这个变量显然就不再是新的了。Swift 会将此标记为错误,这意味着在你给变量取不同的名字之前,代码无法运行。

这听起来可能有点烦人,但相信我:这是有帮助的!Swift 希望你表达清晰:你是想修改一个已有的变量(如果是这样,第二次及以后就去掉 var),还是想创建一个新变量(如果是这样,就给它取个别的名字)。

最后一点:尽管变量是许多 Swift 程序的核心,但你会发现有时候最好避免使用它们。后面会详细讲这一点!

【可选阅读】为什么 Swift 既有变量又有常量?

作者:Paul Hudson 2020 年 5 月 21 日 已针对 Xcode 16.4 更新

变量是在程序中存储临时数据的好方法,但 Swift 给了我们另一个更好的选择:常量。常量在各方面都和变量一样,只有一个重要区别:一旦被赋值,就不能再改变其值。

Swift 非常喜欢常量,事实上,如果你创建了一个变量但从未修改过它的值,Swift 会建议你使用常量。原因在于避免问题:你创建的任何变量都可以随时被你多次修改,所以你会失去一些控制 —— 你存储的重要用户数据可能在未来的任何时候被删除或替换。

常量不允许我们在赋值后修改其值,所以这有点像和 Swift 签订了一份协议:你在说 “这个值很重要,无论我做什么都不要让我修改它”。当然,你也可以尝试和变量签订同样的协议,但键盘上的一个失误就可能搞砸一切,而 Swift 对此无能为力。只要把 var 改成 let 使用常量,你就是在让 Swift 确保这个值永远不会改变,这也就成了一件你无需再担心的事。

【练习题】变量和常量

问题 1:以下哪些代码行创建了新变量?

选项 A:

swift
message = "早上好,戴夫!"

选项 B:

swift
var operatingSystem = "macOS"

问题 2:以下哪些代码行创建了常量?

选项 A:

swift
let username = "twostraws"

选项 B:

swift
var status = "success"

1.5 如何创建字符串

作者:Paul Hudson 2021 年 11 月 25 日 已针对 Xcode 16.4 更新

当你将文本赋值给常量或变量时,我们称之为 “字符串(string)”—— 可以想象成一串拼字游戏的字母牌串在一起组成一个单词。

Swift 的字符串以双引号开始和结束,而引号内部的内容则由你决定。你可以使用简短的字母文本,像这样:

swift
let actor = "Denzel Washington"

你也可以使用标点符号、表情符号和其他字符,例如:

swift
let filename = "paris.jpg"
let result = "⭐️ You win! ⭐️"

你甚至可以在字符串中使用其他双引号,只要注意在它们前面加一个反斜杠,这样 Swift 就会明白这些双引号是字符串内部的内容,而不是用来结束字符串的:

swift
let quote = "Then he tapped a sign saying \"Believe\" and walked away."

别担心 —— 如果你漏掉了反斜杠,Swift 肯定会大声提示你的代码有问题。

字符串的长度没有实际限制,这意味着你可以用一个字符串来存储非常长的内容,比如莎士比亚的全部作品。不过,你会发现 Swift 不喜欢字符串中有换行符。所以,下面这种代码是不允许的:

swift
let movie = "A day in
the life of an
Apple engineer"

但这并不意味着你不能创建跨多行的字符串,只是 Swift 需要你对它们进行特殊处理:不是在字符串两边各用一组引号,而是用三组引号,像这样:

swift
let movie = """
A day in
the life of an
Apple engineer
"""

这种多行字符串并不常用,但至少你知道该怎么做了:开头和结尾的三重引号各占一行,中间是你的字符串内容。

创建字符串后,你会发现 Swift 提供了一些有用的功能来处理其内容。随着学习的深入,你会了解更多这样的功能,但这里我想先介绍三个。

首先,你可以在变量或常量名后面加上.count来获取字符串的长度:

swift
print(actor.count)

因为actor的内容是 “Denzel Washington”,所以这会输出 17—— 包括名字中的每个字母,以及中间的空格。

如果你不想直接打印字符串的长度,也可以把它赋值给另一个常量,像这样:

swift
let nameLength = actor.count
print(nameLength)

第二个有用的功能是uppercased(),它会返回一个相同的字符串,但其中所有字母都变成大写:

swift
print(result.uppercased())

是的,这里需要加上圆括号,而count不需要。原因随着你的学习会变得更清楚,但在 Swift 学习的初期,我们可以这样简单理解:如果你是让 Swift 读取一些数据,就不需要圆括号;但如果是让 Swift 执行一些操作,就需要圆括号。随着学习的深入,你会发现这并不完全准确,但目前这样理解足以让你继续学习下去。

最后一个有用的字符串功能叫做hasPrefix(),它可以告诉我们一个字符串是否以我们指定的某些字母开头:

swift
print(movie.hasPrefix("A day"))

还有一个对应的hasSuffix()功能,它用来检查字符串是否以某些文本结尾:

swift
print(filename.hasSuffix(".jpg"))

重要提示: Swift 中的字符串是区分大小写的,这意味着使用filename.hasSuffix(".JPG")会返回 false,因为字符串中的字母是小写的。

字符串在 Swift 中功能非常强大,我们这里只是触及了它们所能做的事情的表面!

【可选阅读】为什么 Swift 需要多行字符串?

作者:Paul Hudson 2020 年 5 月 28 日 已针对 Xcode 16.4 更新

Swift 的标准字符串以引号开始和结束,但绝不能包含任何换行符。例如,这是一个标准字符串:

swift
var quote = "Change the world by being yourself"

对于短小的文本片段来说,这没什么问题,但如果你想存储大量文本,在源代码中就会显得很不美观。这就是多行字符串的用武之地:如果你使用三重引号,就可以根据需要将字符串写成任意多行,这意味着文本在代码中仍然易于阅读:

swift
var burns = """
The best laid schemes
O’ mice and men
Gang aft agley
"""

Swift 会将字符串中的这些换行符视为文本本身的一部分,所以这个字符串实际上包含三行内容。

提示: 有时你可能希望在代码中使用长字符串而不换行,但这种情况相当少见。具体来说,如果你打算与他人共享代码,这一点往往很重要 —— 如果他们在你的程序中看到一条错误信息,可能会想在你的代码中搜索它,而如果你的代码将其拆分成了多行,他们的搜索可能会失败。

【练习题】多行字符串

问题 1/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var burns = """
The best laid schemes
o' mice an' men
gang aft agley
"""

问题 2/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var shakespeare = """
To be or not to be
that is the question
"""

问题 3/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var joseph = """
When I am an old woman,
I shall wear purple
with a red hat that doesn't go,
and doesn't suit me
"""

问题 4/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var eliot = "This is the way the world ends
Not with a bang but with a whimper"

问题 5/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var tennyson = """
Tis better to have loved
and lost than never
 to have loved at all
"""

问题 6/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var lear = "The Owl and the Pussy-cat went to sea
In a beautiful pea-green boat,
They took some honey, and plenty of money,
Wrapped up in a five-pound note."

问题 7/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var wordsworth = """
I wandered lonely as a cloud
that floats on high
o'er vales and hills
"""

问题 8/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var coleridge = """
Water, water, everywhere
and not a drop to drink"""

问题 9/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var henley = """I am the master of my fate
I am the captain of my soul"""

问题 10/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var rossetti = """
For if the darkness and corruption leave
A vestige of the thoughts that once I had,
Better by far you should forget and smile
Than that you should remember and be sad.
"""

问题 11/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var shelley = "My name is Ozymandias, King of Kings
Look on my works, ye mighty, and despair!"

问题 12/12:这段代码正确地创建了多行字符串 —— 对还是错?

swift
var brooke = ""If I should die,
think only this of me
There is some corner of a foreign field
That is forever England."

1.6 如何存储整数

作者:Paul Hudson 2022 年 5 月 12 日 已针对 Xcode 16.4 更新

当你处理像 3、5、50 或 500 万这样的整数时,你所处理的是 Swift 中称为整数的类型,简称为Int—— 如果你好奇的话,“integer” 源自拉丁语,意思是 “完整的”。

创建一个新的整数和创建一个字符串很像:根据你想要常量还是变量来使用letvar,提供一个名称,然后给它赋值。例如,我们可以像这样创建一个score常量:

swift
let score = 10

整数可以非常大 —— 超过十亿、万亿、千万亿,甚至达到百万亿,也可以非常小 —— 它们可以存储小到百万亿的负数。

当你手工写出数字时,可能很难看清具体数值。例如,这个数字是多少?

swift
let reallyBig = 100000000

如果我们手工写这个数字,可能会写成 “100,000,000”,这时就很清楚这是 1 亿。Swift 也有类似的功能:你可以使用下划线_来随意分隔数字。

所以,我们可以把上面的代码改成这样:

swift
let reallyBig = 100_000_000

Swift 其实并不在意下划线的使用方式,所以如果你想,也可以这样写:

swift
let reallyBig = 1_00__00___00____00

最终结果是一样的:reallyBig被设置为一个值为 100,000,000 的整数。

当然,你也可以通过学校里学过的算术运算符,用其他整数来创建新的整数:+用于加法,-用于减法,*用于乘法,/用于除法。

例如:

swift
let lowerScore = score - 2
let higherScore = score + 10
let doubledScore = score * 2
let squaredScore = score * score
let halvedScore = score / 2
print(score)

除了每次都创建新的常量,Swift 还有一些特殊的操作,可以以某种方式调整一个整数,并将结果赋回给原来的数字。

例如,这里创建了一个值为 10 的counter变量,然后给它加 5:

swift
var counter = 10
counter = counter + 5

不用写成counter = counter + 5,你可以使用简写运算符+=,它可以直接把一个数加到对应的整数上:

swift
counter += 5
print(counter)

这两种写法效果完全一样,只是后者更简洁。我们把这些称为复合赋值运算符,它们还有其他形式:

swift
counter *= 2
print(counter)
counter -= 10
print(counter)
counter /= 2
print(counter)

在结束关于整数的内容之前,我想最后提一点:和字符串一样,整数也有一些有用的附加功能。例如,你可以调用整数的isMultiple(of:)方法来判断它是否是另一个整数的倍数。

所以,我们可以这样判断 120 是否是 3 的倍数:

swift
let number = 120
print(number.isMultiple(of: 3))

我在这里是对一个常量调用isMultiple(of:)方法,但你也可以直接使用数字:

swift
print(120.isMultiple(of: 3))

【练习题】字符串和整数

问题 1/6:哪段代码创建了一个整数?

选项 1:

swift
var mortgageRemaining = 100_000

选项 2:

swift
var dogBreed = "samoyed"

问题 2/6:哪段代码创建了一个整数?

选项 1:

swift
var speed = 88

选项 2:

swift
var age = "23"

问题 3/6:哪段代码创建了一个整数?

选项 1:

swift
var repeatCount = 82

选项 2:

swift
var selectedWood = "mahogany"

问题 4/6:哪段代码创建了一个整数?

选项 1:

swift
var highScore = 328_556

选项 2:

swift
var sizeInInches = "27"

问题 5/6:哪段代码创建了一个整数?

选项 1:

swift
var currentSong = "Rainbow to the Stars"

选项 2:

swift
var power = 9001

问题 6/6:哪段代码创建了一个整数?

选项 1:

swift
var winner = "Miguel"

选项 2:

swift
var rating = 5

1.7 如何存储小数

作者:Paul Hudson 2021 年 10 月 1 日 已针对 Xcode 16.4 更新

当你处理诸如 3.1、5.56 或 3.141592654 之类的小数时,你所处理的是 Swift 中所谓的浮点数。这个名称源于计算机存储这些数字的复杂方式:计算机试图在相同的存储空间内存储像 123,456,789 这样非常大的数和像 0.0000000001 这样非常小的数,而实现这一点的唯一方法是根据数字的大小移动小数点的位置。

这种存储方式使得小数对程序员来说是出了名的棘手,通过两行 Swift 代码你就能略知一二:

swift
let number = 0.1 + 0.2
print(number)

运行这段代码时,它不会打印出 0.3。相反,它会打印出 0.30000000000000004—— 也就是 0.3 后面跟着 15 个 0,再加上一个 4,原因嘛…… 就像我说的,这很复杂。

稍后我会详细解释为什么会这么复杂,但首先让我们关注重要的内容。

首先,当你创建一个浮点数时,Swift 会将其视为Double类型。Double是 “双精度浮点数” 的缩写,我知道这个名字很奇怪 —— 多年来,我们处理浮点数的方式发生了很大变化,尽管 Swift 在简化这一点上做得很好,但你有时可能会遇到一些更复杂的旧代码。在这种情况下,这意味着 Swift 分配的存储空间是一些较旧语言的两倍,这使得Double可以存储非常大的数。

其次,Swift 认为小数与整数是完全不同的数据类型,这意味着你不能将它们混合使用。毕竟,整数总是 100% 精确的,而小数则不是,所以除非你明确要求,否则 Swift 不会允许你将两者混合使用。

实际上,这意味着你不能做诸如将整数与小数相加之类的操作,因此下面这种代码会产生错误:

swift
let a = 1
let b = 2.0
let c = a + b

是的,我们能看出b实际上只是伪装成小数的整数 2,但 Swift 仍然不允许这段代码运行。这被称为类型安全:Swift 不会让我们意外地混合不同类型的数据。

如果你想让它们可以相加,你需要明确告诉 Swift,要么将b中的Double类型视为Int类型:

swift
let c = a + Int(b)

要么将a中的Int类型视为Double类型:

swift
let c = Double(a) + b

第三,Swift 会根据你提供的数字来决定你想要创建的是Double类型还是Int类型 —— 如果数字中有小数点,那它就是Double类型,否则就是Int类型。是的,即便是小数点后面的数字都是 0 也不例外。

例如:

swift
let double1 = 3.1
let double2 = 3131.3131
let double3 = 3.0
let int1 = 3

结合类型安全,这意味着一旦 Swift 确定了某个常量或变量的数据类型,它就必须始终存储该类型的数据。这意味着下面这段代码是可行的:

swift
var name = "Nicolas Cage"
name = "John Travolta"

但下面这种代码则不行:

swift
var name = "Nicolas Cage"
name = 57

这段代码告诉 Swiftname将存储一个字符串,但随后却试图在其中放入一个整数。

最后,小数拥有与整数相同的运算符和复合赋值运算符:

swift
var rating = 5.0
rating *= 2

许多较旧的 API 使用一种略有不同的方式来存储小数,称为CGFloat。幸运的是,Swift 允许我们在任何需要CGFloat的地方使用常规的Double数,所以尽管你有时会看到CGFloat,但你可以忽略它。

如果你好奇的话,浮点数复杂的原因是计算机试图使用二进制来存储复杂的数字。例如,我们知道 1 除以 3 会得到 1/3,但这在二进制中无法存储,所以系统被设计成创建非常接近的近似值。这种方式效率极高,而且误差非常小,通常无关紧要,但至少你知道了为什么 Swift 不允许我们意外地混合使用IntDouble了!

【可选阅读】为什么 Swift 既需要 Double 又需要 Int?

作者:Paul Hudson 2020 年 7 月 19 日 已针对 Xcode 16.4 更新

Swift 为我们提供了几种在代码中存储数字的不同方式,它们旨在解决不同的问题。Swift 不允许我们将它们混合使用,因为这样做肯定会导致问题。

你将使用的两种主要数字类型称为整数(integers)和双精度浮点数(doubles)。整数存储整数,例如 0、1、-100 和 6500 万,而双精度浮点数存储小数,例如 0.1、-1.001 和 3.141592654。

创建数字变量时,Swift 会根据你是否包含小数点来决定将其视为整数还是双精度浮点数。例如:

swift
var myInt = 1
var myDouble = 1.0

如你所见,它们都包含数字 1,但前者是整数,后者是双精度浮点数。

现在,既然它们都包含数字 1,你可能会想为什么我们不能把它们相加 —— 为什么我们不能写var total = myInt + myDouble?答案是 Swift 在谨慎行事:我们都知道 1 加 1.0 等于 2,但你的双精度浮点数是一个变量,所以它可能会被修改为 1.1、3.5 或其他值。Swift 怎么能确定将整数与双精度浮点数相加是安全的呢 —— 它怎么能确定你不会丢失 0.1 或 0.5 这样的小数部分呢?

答案是它无法确定这是安全的,这就是为什么不允许这样做。一开始你可能会觉得很麻烦,但相信我:这是有帮助的。

【可选阅读】为什么 Swift 是一种类型安全的语言?

作者:Paul Hudson 2020 年 5 月 29 日 已针对 Xcode 16.4 更新

Swift 允许我们创建字符串、整数等类型的变量,也可以创建许多其他类型的数据变量。当你创建一个变量时,Swift 可以根据你赋给它的数据类型来确定该变量的类型,从那以后,这个变量将始终是那种特定的类型。

例如,下面创建了一个名为meaningOfLife、值为 42 的新变量:

swift
var meaningOfLife = 42

因为我们给meaningOfLife赋的初始值是 42,所以 Swift 会将它指定为整数类型 —— 一种整数。它是一个变量,这意味着我们可以根据需要经常更改它的值,但我们不能更改它的类型:它将始终是一个整数。

这在构建应用程序时非常有帮助,因为这意味着 Swift 会确保我们不会在数据上犯错误。例如,我们不能这样写:

swift
meaningOfLife = "Forty two"

这试图将一个字符串赋给一个整数类型的变量,这是不允许的。虽然我们很少犯这种明显的错误,但你会发现这种类型安全在你编写 Swift 代码的每一天都能帮上忙。

想想看:我们只是创建了一个变量,然后试图改变它的类型,这显然会失败。但随着你的程序规模和复杂度的增长,你不可能时刻记住所有变量的类型,所以实际上我们是把这项工作交给了 Swift。

恭喜你完成了第一天的学习!是的,这只是第一天,但现在你获得的动力越多,当事情变得更困难时,你就越能坚持下去!

本站使用 VitePress 制作