Swift数据类型深入探索
Swift 基础数据类型
整数类型
在 Swift 中,整数类型用于表示没有小数部分的数字。根据表示范围的不同,Swift 提供了多种整数类型。
- 有符号整数
- Int8:8 位有符号整数,范围从 -128 到 127。
- Int16:16 位有符号整数,范围从 -32768 到 32767。
- Int32:32 位有符号整数,范围从 -2147483648 到 2147483647。
- Int64:64 位有符号整数,范围从 -9223372036854775808 到 9223372036854775807。
- Int:与平台相关的有符号整数类型。在 32 位平台上等价于 Int32,在 64 位平台上等价于 Int64。在大多数情况下,推荐使用 Int 类型,因为它能保证代码在不同平台上的一致性。 示例代码:
let int8Value: Int8 = -128 let int16Value: Int16 = 32767 let int32Value: Int32 = -2147483648 let int64Value: Int64 = 9223372036854775807 let intValue: Int = 100
- 无符号整数
- UInt8:8 位无符号整数,范围从 0 到 255。
- UInt16:16 位无符号整数,范围从 0 到 65535。
- UInt32:32 位无符号整数,范围从 0 到 4294967295。
- UInt64:64 位无符号整数,范围从 0 到 18446744073709551615。
- UInt:与平台相关的无符号整数类型。在 32 位平台上等价于 UInt32,在 64 位平台上等价于 UInt64。 示例代码:
let uint8Value: UInt8 = 255 let uint16Value: UInt16 = 65535 let uint32Value: UInt32 = 4294967295 let uint64Value: UInt64 = 18446744073709551615 let uintValue: UInt = 200
浮点数类型
浮点数类型用于表示带有小数部分的数字。Swift 提供了两种主要的浮点数类型:
- Float:32 位浮点数,通常适用于表示不需要非常高精度的小数。它可以精确到大约 6 到 7 位小数。
示例代码:
let floatValue: Float = 3.14159
- Double:64 位浮点数,精度更高,适用于需要更高精度的计算。它可以精确到大约 15 到 17 位小数。在大多数情况下,推荐使用 Double 类型,因为现代 CPU 对 64 位浮点数的运算效率也很高。
示例代码:
let doubleValue: Double = 3.141592653589793
布尔类型
布尔类型(Bool)只有两个值:true
和 false
,用于表示逻辑判断的结果。在 Swift 中,布尔类型是一等公民,很多控制流语句(如 if
、while
等)都依赖布尔值来决定程序的执行流程。
示例代码:
let isDone: Bool = true
if isDone {
print("任务已完成")
} else {
print("任务未完成")
}
字符类型
字符类型(Character)用于表示单个 Unicode 字符。在 Swift 中,一个 Character
实例可以表示一个字母、数字、标点符号,甚至是一个 emoji。
示例代码:
let letter: Character = "A"
let digit: Character = "5"
let punctuation: Character = "!"
let emoji: Character = "😀"
与其他一些编程语言不同,Swift 的 Character
类型不是简单的 ASCII 字符,而是完整的 Unicode 字符。这意味着它可以处理世界上几乎所有语言的字符。
复合数据类型
数组
数组是一种有序的相同类型元素的集合。在 Swift 中,数组类型有两种表示方式:Array<Element>
和 [Element]
,其中 Element
是数组中元素的类型。
- 创建数组
- 字面量创建:可以使用数组字面量来创建数组,即把一组元素用方括号
[]
括起来。 示例代码:
let numbers: [Int] = [1, 2, 3, 4, 5] let names: [String] = ["Alice", "Bob", "Charlie"]
- 初始化器创建:也可以使用数组的初始化器来创建数组。 示例代码:
let emptyArray: [Int] = [] let repeatedArray = Array(repeating: 0, count: 5) // 创建一个包含 5 个 0 的数组
- 字面量创建:可以使用数组字面量来创建数组,即把一组元素用方括号
- 访问和修改数组元素
- 访问元素:可以通过下标(index)来访问数组中的元素,下标从 0 开始。 示例代码:
let numbers: [Int] = [1, 2, 3, 4, 5] let firstNumber = numbers[0]
- 修改元素:通过下标也可以修改数组中的元素。 示例代码:
var numbers: [Int] = [1, 2, 3, 4, 5] numbers[2] = 100
- 数组操作
- 添加元素:可以使用
append(_:)
方法向数组末尾添加一个元素,或者使用+=
运算符将一个数组追加到另一个数组。 示例代码:
var numbers: [Int] = [1, 2, 3] numbers.append(4) numbers += [5, 6]
- 删除元素:使用
remove(at:)
方法可以删除指定下标的元素,removeLast()
方法删除数组的最后一个元素。 示例代码:
var numbers: [Int] = [1, 2, 3, 4, 5] numbers.remove(at: 2) numbers.removeLast()
- 添加元素:可以使用
集合
集合是一种无序的、唯一元素的集合。Swift 提供了 Set
类型来表示集合。集合类型的表示方式为 Set<Element>
。
- 创建集合
- 字面量创建:可以使用集合字面量来创建集合,即把一组元素用方括号
[]
括起来,但元素之间没有顺序。 示例代码:
let numbers: Set<Int> = [1, 2, 3, 3, 4] // 集合会自动去除重复元素,实际集合为 [1, 2, 3, 4] let letters: Set<Character> = ["a", "b", "c"]
- 初始化器创建:也可以使用集合的初始化器来创建集合。 示例代码:
let emptySet: Set<Int> = [] let setFromArray = Set([1, 2, 3, 4, 4]) // 同样会去除重复元素
- 字面量创建:可以使用集合字面量来创建集合,即把一组元素用方括号
- 访问和修改集合元素
- 访问元素:由于集合是无序的,不能通过下标来访问元素。但可以通过遍历集合来访问所有元素。 示例代码:
let numbers: Set<Int> = [1, 2, 3, 4] for number in numbers { print(number) }
- 修改元素:可以使用
insert(_:)
方法向集合中插入一个元素,使用remove(_:)
方法删除指定元素。 示例代码:
var numbers: Set<Int> = [1, 2, 3] numbers.insert(4) numbers.remove(2)
- 集合操作
- 集合运算:集合支持多种集合运算,如并集、交集、差集等。 示例代码:
let setA: Set<Int> = [1, 2, 3] let setB: Set<Int> = [3, 4, 5] let unionSet = setA.union(setB) // [1, 2, 3, 4, 5] let intersectionSet = setA.intersection(setB) // [3] let differenceSet = setA.subtracting(setB) // [1, 2]
字典
字典是一种无序的键值对集合,其中每个键都是唯一的。Swift 中字典类型的表示方式为 Dictionary<Key, Value>
或 [Key: Value]
,其中 Key
是键的类型,Value
是值的类型。
- 创建字典
- 字面量创建:可以使用字典字面量来创建字典,即把一组键值对用方括号
[]
括起来,键和值之间用冒号:
分隔。 示例代码:
let scores: [String: Int] = ["Alice": 85, "Bob": 90, "Charlie": 78] let userInfo: [String: Any] = ["name": "John", "age": 30, "isAdmin": false]
- 初始化器创建:也可以使用字典的初始化器来创建字典。 示例代码:
let emptyDictionary: [String: Int] = [:] let dictionaryFromPairs = Dictionary([("one", 1), ("two", 2)])
- 字面量创建:可以使用字典字面量来创建字典,即把一组键值对用方括号
- 访问和修改字典元素
- 访问元素:可以通过键来访问字典中的值,如果键不存在,则返回
nil
。 示例代码:
let scores: [String: Int] = ["Alice": 85, "Bob": 90, "Charlie": 78] let aliceScore = scores["Alice"]
- 修改元素:通过键可以修改字典中对应的值,如果键不存在,则会添加一个新的键值对。 示例代码:
var scores: [String: Int] = ["Alice": 85, "Bob": 90, "Charlie": 78] scores["Alice"] = 95 scores["David"] = 80
- 访问元素:可以通过键来访问字典中的值,如果键不存在,则返回
- 字典操作
- 删除元素:使用
removeValue(forKey:)
方法可以删除指定键的键值对。 示例代码:
var scores: [String: Int] = ["Alice": 85, "Bob": 90, "Charlie": 78] scores.removeValue(forKey: "Bob")
- 遍历字典:可以使用
for - in
循环遍历字典的键值对、键或值。 示例代码:
let scores: [String: Int] = ["Alice": 85, "Bob": 90, "Charlie": 78] for (name, score) in scores { print("\(name) 的分数是 \(score)") } for name in scores.keys { print(name) } for score in scores.values { print(score) }
- 删除元素:使用
枚举类型
枚举是一种定义一组相关值的方式。在 Swift 中,枚举比 C 语言中的枚举更加强大,不仅可以定义简单的命名常量,还可以关联值,甚至定义方法。
- 简单枚举
- 示例代码:
在这个例子中,enum CompassPoint { case north case south case east case west } let direction: CompassPoint = .north
CompassPoint
是一个枚举类型,它有四个成员:north
、south
、east
和west
。可以通过enumName.memberName
的方式来引用枚举成员。 - 关联值枚举
- 关联值枚举允许在枚举成员中存储额外的数据。
- 示例代码:
在这个例子中,enum Barcode { case upc(Int, Int, Int, Int) case qrCode(String) } var productBarcode = Barcode.upc(8, 85909, 51226, 3) productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
Barcode
枚举有两个成员,upc
关联了四个Int
值,qrCode
关联了一个String
值。可以根据需要为枚举成员设置不同的关联值。 - 原始值枚举
- 原始值枚举为每个枚举成员提供一个默认值,这个值的类型必须是相同的,如
Int
、String
等。 - 示例代码:
在这个例子中,enum Planet: Int { case mercury = 1 case venus case earth case mars case jupiter case saturn case uranus case neptune } let earthOrder = Planet.earth.rawValue
Planet
枚举的成员都有一个Int
类型的原始值,从mercury
的 1 开始自动递增。可以通过memberName.rawValue
来获取枚举成员的原始值。 - 原始值枚举为每个枚举成员提供一个默认值,这个值的类型必须是相同的,如
- 枚举方法
- 枚举可以定义实例方法和类型方法。
- 示例代码:
在这个例子中,enum Weekday { case sunday, monday, tuesday, wednesday, thursday, friday, saturday func isWeekend() -> Bool { switch self { case .sunday, .saturday: return true default: return false } } static func numberOfDays() -> Int { return 7 } } let today = Weekday.monday let isWeekend = today.isWeekend() let daysInWeek = Weekday.numberOfDays()
Weekday
枚举定义了一个实例方法isWeekend()
用于判断是否是周末,还定义了一个类型方法numberOfDays()
用于返回一周的天数。
结构体类型
结构体是一种复合数据类型,它可以包含多个不同类型的属性和方法。在 Swift 中,结构体是值类型,当结构体被赋值或传递给函数时,会进行值的拷贝。
- 定义结构体
- 示例代码:
在这个例子中,struct Point { var x: Int var y: Int } let point1 = Point(x: 10, y: 20)
Point
结构体定义了两个属性x
和y
,都是Int
类型。可以通过初始化器Point(x:y:)
来创建结构体实例。 - 结构体属性
- 存储属性:像上面
Point
结构体中的x
和y
就是存储属性,它们用于存储结构体实例的数据。 - 计算属性:计算属性不存储实际的值,而是通过计算来返回一个值。
- 示例代码:
在这个例子中,struct Rectangle { var width: Int var height: Int var area: Int { return width * height } } let rect = Rectangle(width: 5, height: 10) let rectArea = rect.area
Rectangle
结构体的area
属性是一个计算属性,它通过width
和height
计算得出矩形的面积。 - 存储属性:像上面
- 结构体方法
- 结构体可以定义实例方法和类型方法。
- 示例代码:
在这个例子中,struct Circle { var radius: Double func circumference() -> Double { return 2 * .pi * radius } static func description() -> String { return "这是一个圆的结构体" } } let circle = Circle(radius: 5.0) let circleCircumference = circle.circumference() let circleDesc = Circle.description()
Circle
结构体定义了一个实例方法circumference()
用于计算圆的周长,还定义了一个类型方法description()
用于返回结构体的描述。 - 结构体初始化器
- 结构体默认会有一个成员逐一初始化器,它使用结构体的属性名作为参数名。
- 示例代码:
也可以自定义初始化器来满足特定的初始化需求。struct Person { var name: String var age: Int } let person = Person(name: "John", age: 30)
- 示例代码:
在这个例子中,struct Rectangle { var width: Int var height: Int init(sideLength: Int) { width = sideLength height = sideLength } } let square = Rectangle(sideLength: 10)
Rectangle
结构体自定义了一个初始化器init(sideLength:)
,用于创建正方形(宽和高相等)的矩形实例。
类类型
类是一种更加复杂的复合数据类型,它支持继承、多态等面向对象编程的特性。与结构体不同,类是引用类型,当类的实例被赋值或传递给函数时,传递的是引用,而不是值的拷贝。
- 定义类
- 示例代码:
在这个例子中,class Animal { var name: String var age: Int init(name: String, age: Int) { self.name = name self.age = age } func makeSound() { print("动物发出声音") } } let dog = Animal(name: "Buddy", age: 3)
Animal
类定义了两个属性name
和age
,一个初始化器init(name:age:)
用于初始化属性,还有一个实例方法makeSound()
。 - 类的继承
- 一个类可以继承另一个类的属性和方法。
- 示例代码:
在这个例子中,class Dog: Animal { var breed: String init(name: String, age: Int, breed: String) { self.breed = breed super.init(name: name, age: age) } override func makeSound() { print("汪汪汪") } } let poodle = Dog(name: "Max", age: 2, breed: "Poodle") poodle.makeSound()
Dog
类继承自Animal
类,它添加了一个新的属性breed
,并重写了makeSound()
方法。在Dog
类的初始化器中,通过super.init(name:age:)
调用了父类的初始化器。 - 多态
- 多态是指不同类的对象对同一消息做出不同响应的能力。在 Swift 中,通过继承和方法重写来实现多态。
- 示例代码:
在这个例子中,class Cat: Animal { override func makeSound() { print("喵喵喵") } } let animals: [Animal] = [Dog(name: "Buddy", age: 3, breed: "Labrador"), Cat(name: "Whiskers", age: 1)] for animal in animals { animal.makeSound() }
animals
数组包含了Dog
和Cat
类的实例,它们都继承自Animal
类。当遍历数组并调用makeSound()
方法时,会根据实际对象的类型(Dog
或Cat
)来调用相应的重写方法,体现了多态性。 - 类的生命周期
- 初始化:类的初始化过程包括设置初始值和执行必要的准备工作。除了自定义初始化器外,类还可以有便利初始化器,它必须调用同一个类的指定初始化器。
- 析构:当类的实例被释放时,会调用析构器(
deinit
),用于执行一些清理工作,如释放资源等。 - 示例代码:
在这个例子中,class FileHandler { var filePath: String init(filePath: String) { self.filePath = filePath print("打开文件 \(filePath)") } deinit { print("关闭文件 \(filePath)") } } var file = FileHandler(filePath: "example.txt") file = nil // 释放 file 实例,调用析构器
FileHandler
类的初始化器打印打开文件的信息,析构器打印关闭文件的信息。当file
被赋值为nil
时,实例被释放,析构器被调用。
可选类型
可选类型是 Swift 中一个非常重要的概念,用于表示一个值可能存在,也可能不存在。在 Swift 中,通过在类型后面加上 ?
来定义可选类型。
- 定义可选类型
- 示例代码:
在这个例子中,var optionalNumber: Int? optionalNumber = 10
optionalNumber
是一个可选的Int
类型,初始值为nil
,之后可以赋值为一个Int
值。 - 可选绑定
- 可选绑定用于判断一个可选值是否存在,如果存在,则将其解包并赋值给一个临时常量或变量。
- 示例代码:
在这个例子中,通过var optionalNumber: Int? = 10 if let number = optionalNumber { print("解包后的数字: \(number)") } else { print("值不存在") }
if let
进行可选绑定,如果optionalNumber
有值,则将其解包并赋值给number
,然后执行if
块中的代码。 - 隐式解包可选类型
- 隐式解包可选类型通过在类型后面加上
!
来定义。它与普通可选类型类似,但在使用时不需要显式解包。通常用于在初始化后确定不会为nil
的值。 - 示例代码:
但要注意,如果隐式解包可选类型在使用时为var implicitlyUnwrappedOptional: Int! = 20 let value = implicitlyUnwrappedOptional + 10 // 不需要显式解包
nil
,会导致运行时错误。 - 隐式解包可选类型通过在类型后面加上
- 可选链
- 可选链是一种在可能为
nil
的值上调用属性、方法或下标脚本的方法。如果值为nil
,则链中的调用会自动失败并返回nil
。 - 示例代码:
在这个例子中,class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() let rooms = john.residence?.numberOfRooms
john.residence
是一个可选值,如果它为nil
,则john.residence?.numberOfRooms
会返回nil
,而不会导致运行时错误。 - 可选链是一种在可能为
类型别名
类型别名是为现有类型定义一个替代名称的方式。在 Swift 中,使用 typealias
关键字来定义类型别名。
- 基本类型别名
- 示例代码:
在这个例子中,typealias Age = Int let myAge: Age = 30
Age
是Int
类型的别名,myAge
的类型实际上是Int
,但使用Age
作为类型名可以使代码更具可读性。 - 复杂类型别名
- 示例代码:
在这个例子中,typealias Point2D = (x: Int, y: Int) let origin: Point2D = (0, 0)
Point2D
是一个元组类型(x: Int, y: Int)
的别名,使用Point2D
可以更方便地表示二维点。- 对于函数类型也可以定义别名。
- 示例代码:
在这个例子中,typealias MathOperation = (Int, Int) -> Int func add(_ a: Int, _ b: Int) -> Int { return a + b } let operation: MathOperation = add let result = operation(3, 5)
MathOperation
是一个函数类型(Int, Int) -> Int
的别名,它表示接受两个Int
参数并返回一个Int
结果的函数。add
函数符合这个类型,将其赋值给operation
后,可以通过operation
来调用add
函数。
通过对 Swift 各种数据类型的深入探索,我们可以更好地理解如何根据不同的需求选择合适的数据类型,从而编写出高效、清晰的 Swift 代码。无论是简单的基础数据类型,还是复杂的复合数据类型、枚举、结构体和类,都在 Swift 的编程世界中有着各自独特的用途和优势。