数据类型

目录

数据类型

数据类型在编程中非常重要, 因为它们帮助我们明确和控制存储在计算机内存中的数据的性质和行为。 具体来说, 数据类型的重要性体现在以下几个方面:

  • 内存管理: 不同数据类型占用的内容空间不同。
  • 数据安全性和准确性: 使用合适的数据类型可以防止数据被错误地操作。 例如, 将整数作为浮点数处理可能会导致精度丢失, 将字符串作为整数处理则可能导致程序崩溃或出现错误结果。
  • 操作符的适用性: 不同的数据类型适用的操作符可能不同。 比如, 数字类型可以进行加减乘除等数学运算, 而字符串类型则可以进行连接操作。 明确的数据类型可以防止在不适用的情况下使用操作符, 避免程序错误。
  • 提高代码可读性: 定义数据类型使得代码更加自解释。 程序员或其他阅读代码的人可以通过变量的类型推断出变量的用途和意图, 这有助于维护和调试代码。

Swift 提供了许多基本数据类型, 包括表示整数的 Int、 表示浮点值的 Double、 表示布尔值的 Bool 和表示文本的 String 。Swift 还提供了三种主要集合类型(Array、Set 和 Dictionary)的强大版本。 这些内容我们一个一个来说。

整数

整数是没有小数部分的数字,可以有符号,也可以无符号。

import Foundation

// 正整数
let age = 18

// 负整数
let temp = -253

Int

Swift提供了不同位数的整数,有8位,16位,32位和64位。 不过大部分时候, 我们不需要在代码中使用特定大小的整数。

Swift有一个Int类型, 它的大小和平台位数相关。 在32位系统上, Int大小就是Int32; 在64位系统上, Int大小就是Int64。

即使在32位平台,Int可以存储的整数范围也有 -2,147,483,648 到 2,147,483,647 。 所以完全不用担心。

import Foundation

var age: Int
age = 110101010101
print(age)

浮点数

浮点数是带有小数部分的数字, 比如3.14, -273.15等。

与整数类型相比, 浮点数表示的数值范围更广。 Swift提供了两种浮点数类型: Double表示64位浮点数, Float表示32位浮点数。

Double的精度要大于Float,大部分时候使用Double就可以了。

import Foundation

var pi: Float
pi = 3.14

var avgScore: Double
avgScore = 145.312

print(pi)
print(avgScore)

运行结果

3.14
145.312

类型推断

实际编码时, 我们不需要指定每个变量和常量的类型。 因为Swift会使用类型推断, 确定适当的类型。

import Foundation

let userName = "hzclog"
let age = 18
let totalScore = 450.5

print("学生:\(userName),年龄:\(age),总分:\(totalScore)")

运行结果

学生:hzclog,年龄:18,总分:450.5

需要注意的是,不要传递错误类型的值给变量

import Foundation

var age: Int
age = 18
print(age)

age = 3.14 // 这里会报错,赋值的类型不对。
print(age)

数字类型转换

上面的例子可以看出, 不同类型的数字不能相互混淆。 如果我们要处理的数据类型不一致, 可以通过类型转换的方式处理。

下面的代码不能运行。 因为我们尝试把整数类型的english常量, 和浮点数的math相加。

import Foundation

let english = 78
let math = 98.5
let sum = english + math
print("总分是:\(sum)")

既然这样, 我们可以使用Double将整数转化为浮点数。

import Foundation

let english = 78
let math = 98.5
let sum = Double(english) + math
print("总分是:\(sum)")

现在我们就可以得出结果了。

总分是: 176.5


如果小数部分不需要,Int可以将浮点数转换为整数。

import Foundation

let english = 78
let math = 98.5
let sum = english + Int(math)
print("总分是:\(sum)")

输出的结果是:

总分是: 176

⚠️

需要注意的是: 使用Int初始化整数值, 浮点数的小数部分会直接截断, 这里可没有四舍五入的规则。

布尔

Swift有基本的布尔类型。 布尔值称为逻辑值, 它们只能为真或者假, 对应常量就是 truefalse

import Foundation

// 是周日
let isSunday = true

// 不是下雨天
let isRainy = false

// 带上类型
let isMale: Bool
isMale = true

元组

元组可以将多个值组合成一个复合值。 元组内的值可以是任何类型, 并且不必彼此属于同一类型。

比如下面这样。

import Foundation

// user的类型就是(String, Int), 对应的值是("hzclog", 18)
let user = ("hzclog", 18)

元组中可以包含任意数量, 不同类型的值。 当我们需要使用元组内容的时候, 可以将其分解为单独的常量或者变量, 然后使用。

具体使用方法看这里。

import Foundation

// user的类型是: (String, Int, String)
let user = ("hzclog", 18, "陕西省西安市")

// 通过圆括号拆解元组
let (userName, userAge, userAddress) = user
print("用户名: \(userName)")
print("年龄: \(userAge)")
print("住址: \(userAddress)")

如果只需要元组的部分值, 可以在分解元组时使用下划线来忽略对应位置的值。

import Foundation

// user的类型是: (String, Int, String)
let user = ("hzclog", 18, "陕西省西安市")

// 只要姓名和住址,不要年龄
let (userName, _, userAddress) = user
print("用户名: \(userName)")
print("住址: \(userAddress)")

如果你学习过其他编程语言, 自然而然会想到索引取值。

索引从左到右, 从0开始。 所以第一个值的索引是0, 第二个值就是1, 以此类推。

import Foundation

// user的类型是: (String, Int, String)
let user = ("hzclog", 18, "陕西省西安市")

print("用户名: \(user.0)") // 索引0对应第一个值,hzclog
print("住址: \(user.2)") // 索引2对应第三个值,陕西省西安市

使用索引的奇怪之处是: 没人喜欢记忆元组里面一堆数据什么位置放什么东西。 最好是像变量userName这样, 起一个好记的名字。

我们确实可以给元组中的值命名, 然后通过名称访问对应的值。

import Foundation

let user = (name: "hzclog", age: 18, address: "陕西省西安市")

print("用户名: \(user.name)")
print("年龄: \(user.age)")
print("住址: \(user.address)")

这样看起来,可以0, 1, 2什么的舒服多了。

💡

元组适用于简单的相关值组。 它们不适合创建复杂的数据结构。 如果你的数据结构可能比较复杂, 请将其建模为类或结构。

可选值

通过刚才的学习, 我们知道Int可以使用给定数据初始化整数。 不过转化出来的数据类型就是Int吗?

编写下面的代码,会在print这一行出现黄颜色的警告信息: Expression implicitly coerced from ‘Int?’ to ‘Any’

import Foundation

let targetStr = "123"
let number = Int(targetStr)
print(number) // 这里输出的不是123,而是Optional(123)

因为尝试将给定的数据转换成Int类型不一定会成功。 如果字符串就是123, 可以转换数字123。 如果里面是hello world, 那会怎样呢?

import Foundation

let targetStr = "hello world"
let number = Int(targetStr)
print(number) // nil

类似Int这样的数据转换器可能会失败。 如果成功返回的就是可选的整数 optional Int, 失败返回nil。

创建可选类型

要创建可选类型, 可以在类型的名称后面加上问号。

比如可选Int类型就是 Int?, 那么这个类型总是包含某个Int值, 或者不包含任何值, 也就是nil。

nil是一个特殊的值, 用于表示变量或者常量没有被赋值。

import Foundation

// userName类型为可选字符串,初始化为hzclog
var userName: String? = "hzclog"

// 因为是可选类型,可以赋值为nil,表示没有任何值
userName = nil

如果声明可选变量时没有赋值, 默认就是nil。

import Foundation

var userName: String?

print(userName) // nil

访问可选值时, 代码必须要处理nil和非nil两种情况。

比如下面这些方法。

提供后备值

可以使用操作符 ?? 提供后备值。 如果??左边的可选值不是nil, 就使用解包的值; 如果是nil, 就使用??右边的值。

import Foundation

var userName: String?

print(userName ?? "hzclog") // 如果userName不是nil,就使用userName的值;否则就使用hzclog。

强制解包

如果nil表示不可恢复的错误, 可以通过 ! 解包获取值。

如果解包出来的值不是nil, 就使用解包值; 如果是nil,则会引发运行时的错误。

import Foundation

let str = "123"
let convertedResult = Int(str)

let number = convertedResult!

print(number)

运行试试。 然后再将str的值换成一个无法转化的字符串, 再试试。

如果你真的有尝试, 就会发现程序错误。 一般情况下, 我们遇到错误会想办法处理它, 不过这是后面的内容, 之后再说。

断言

当你编写一个比较复杂的程序, 希望在执行某些代码之前, 确保某些条件满足时(也就是布尔值true), 就可以使用断言。

如果断言条件求值为true, 代码正常执行; 如果为false, 代码执行结束。

import Foundation

let age = -16

assert(age >= 0, "年龄不可能小于0。") // 这里会出现断言错误:Assertion failed: 年龄不可能小于0。

print("用户的年龄是: \(age)")

这段代码age变量一定需要大于等于0。 所以我们在使用变量输出信息之前先断言, 如果条件满足, 就输出用户年龄; 如果不满足, 就报断言错误。

尝试一下修改代码让断言通过。

下一章

这一章的内容就是这些。 在这一个章节中, 我们了解了这些内容:

  • 数据类型是什么?
  • 数字类型
  • 类型推断与数字类型转换
  • 布尔类型
  • 元组类型
  • 可选值
  • 断言

下一章我们来看看Swift提供的常用操作符有哪些。