MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Swift数据类型深入探索

2023-05-137.4k 阅读

Swift 基础数据类型

整数类型

在 Swift 中,整数类型用于表示没有小数部分的数字。根据表示范围的不同,Swift 提供了多种整数类型。

  1. 有符号整数
    • 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
    
  2. 无符号整数
    • 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 提供了两种主要的浮点数类型:

  1. Float:32 位浮点数,通常适用于表示不需要非常高精度的小数。它可以精确到大约 6 到 7 位小数。 示例代码:
    let floatValue: Float = 3.14159
    
  2. Double:64 位浮点数,精度更高,适用于需要更高精度的计算。它可以精确到大约 15 到 17 位小数。在大多数情况下,推荐使用 Double 类型,因为现代 CPU 对 64 位浮点数的运算效率也很高。 示例代码:
    let doubleValue: Double = 3.141592653589793
    

布尔类型

布尔类型(Bool)只有两个值:truefalse,用于表示逻辑判断的结果。在 Swift 中,布尔类型是一等公民,很多控制流语句(如 ifwhile 等)都依赖布尔值来决定程序的执行流程。 示例代码:

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 是数组中元素的类型。

  1. 创建数组
    • 字面量创建:可以使用数组字面量来创建数组,即把一组元素用方括号 [] 括起来。 示例代码:
    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 的数组
    
  2. 访问和修改数组元素
    • 访问元素:可以通过下标(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
    
  3. 数组操作
    • 添加元素:可以使用 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>

  1. 创建集合
    • 字面量创建:可以使用集合字面量来创建集合,即把一组元素用方括号 [] 括起来,但元素之间没有顺序。 示例代码:
    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]) // 同样会去除重复元素
    
  2. 访问和修改集合元素
    • 访问元素:由于集合是无序的,不能通过下标来访问元素。但可以通过遍历集合来访问所有元素。 示例代码:
    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)
    
  3. 集合操作
    • 集合运算:集合支持多种集合运算,如并集、交集、差集等。 示例代码:
    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 是值的类型。

  1. 创建字典
    • 字面量创建:可以使用字典字面量来创建字典,即把一组键值对用方括号 [] 括起来,键和值之间用冒号 : 分隔。 示例代码:
    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)])
    
  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
    
  3. 字典操作
    • 删除元素:使用 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 语言中的枚举更加强大,不仅可以定义简单的命名常量,还可以关联值,甚至定义方法。

  1. 简单枚举
    • 示例代码:
    enum CompassPoint {
        case north
        case south
        case east
        case west
    }
    let direction: CompassPoint = .north
    
    在这个例子中,CompassPoint 是一个枚举类型,它有四个成员:northsoutheastwest。可以通过 enumName.memberName 的方式来引用枚举成员。
  2. 关联值枚举
    • 关联值枚举允许在枚举成员中存储额外的数据。
    • 示例代码:
    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 值。可以根据需要为枚举成员设置不同的关联值。
  3. 原始值枚举
    • 原始值枚举为每个枚举成员提供一个默认值,这个值的类型必须是相同的,如 IntString 等。
    • 示例代码:
    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 来获取枚举成员的原始值。
  4. 枚举方法
    • 枚举可以定义实例方法和类型方法。
    • 示例代码:
    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 中,结构体是值类型,当结构体被赋值或传递给函数时,会进行值的拷贝。

  1. 定义结构体
    • 示例代码:
    struct Point {
        var x: Int
        var y: Int
    }
    let point1 = Point(x: 10, y: 20)
    
    在这个例子中,Point 结构体定义了两个属性 xy,都是 Int 类型。可以通过初始化器 Point(x:y:) 来创建结构体实例。
  2. 结构体属性
    • 存储属性:像上面 Point 结构体中的 xy 就是存储属性,它们用于存储结构体实例的数据。
    • 计算属性:计算属性不存储实际的值,而是通过计算来返回一个值。
    • 示例代码:
    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 属性是一个计算属性,它通过 widthheight 计算得出矩形的面积。
  3. 结构体方法
    • 结构体可以定义实例方法和类型方法。
    • 示例代码:
    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() 用于返回结构体的描述。
  4. 结构体初始化器
    • 结构体默认会有一个成员逐一初始化器,它使用结构体的属性名作为参数名。
    • 示例代码:
    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:),用于创建正方形(宽和高相等)的矩形实例。

类类型

类是一种更加复杂的复合数据类型,它支持继承、多态等面向对象编程的特性。与结构体不同,类是引用类型,当类的实例被赋值或传递给函数时,传递的是引用,而不是值的拷贝。

  1. 定义类
    • 示例代码:
    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 类定义了两个属性 nameage,一个初始化器 init(name:age:) 用于初始化属性,还有一个实例方法 makeSound()
  2. 类的继承
    • 一个类可以继承另一个类的属性和方法。
    • 示例代码:
    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:) 调用了父类的初始化器。
  3. 多态
    • 多态是指不同类的对象对同一消息做出不同响应的能力。在 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 数组包含了 DogCat 类的实例,它们都继承自 Animal 类。当遍历数组并调用 makeSound() 方法时,会根据实际对象的类型(DogCat)来调用相应的重写方法,体现了多态性。
  4. 类的生命周期
    • 初始化:类的初始化过程包括设置初始值和执行必要的准备工作。除了自定义初始化器外,类还可以有便利初始化器,它必须调用同一个类的指定初始化器。
    • 析构:当类的实例被释放时,会调用析构器(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 中,通过在类型后面加上 ? 来定义可选类型。

  1. 定义可选类型
    • 示例代码:
    var optionalNumber: Int?
    optionalNumber = 10
    
    在这个例子中,optionalNumber 是一个可选的 Int 类型,初始值为 nil,之后可以赋值为一个 Int 值。
  2. 可选绑定
    • 可选绑定用于判断一个可选值是否存在,如果存在,则将其解包并赋值给一个临时常量或变量。
    • 示例代码:
    var optionalNumber: Int? = 10
    if let number = optionalNumber {
        print("解包后的数字: \(number)")
    } else {
        print("值不存在")
    }
    
    在这个例子中,通过 if let 进行可选绑定,如果 optionalNumber 有值,则将其解包并赋值给 number,然后执行 if 块中的代码。
  3. 隐式解包可选类型
    • 隐式解包可选类型通过在类型后面加上 ! 来定义。它与普通可选类型类似,但在使用时不需要显式解包。通常用于在初始化后确定不会为 nil 的值。
    • 示例代码:
    var implicitlyUnwrappedOptional: Int! = 20
    let value = implicitlyUnwrappedOptional + 10 // 不需要显式解包
    
    但要注意,如果隐式解包可选类型在使用时为 nil,会导致运行时错误。
  4. 可选链
    • 可选链是一种在可能为 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 关键字来定义类型别名。

  1. 基本类型别名
    • 示例代码:
    typealias Age = Int
    let myAge: Age = 30
    
    在这个例子中,AgeInt 类型的别名,myAge 的类型实际上是 Int,但使用 Age 作为类型名可以使代码更具可读性。
  2. 复杂类型别名
    • 示例代码:
    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 的编程世界中有着各自独特的用途和优势。