Swift 学习笔记:结构体

73 阅读8分钟

定义

在 Swift 中,结构体是一种复合数据类型,可以封装多个相关的值。你可以使用 struct 关键字来定义一个结构体。

以下是一个结构体的定义示例:

struct Point {
    var x: Double
    var y: Double
}

在这个例子中,我们定义了一个名为 Point 的结构体,它有两个属性:x 和 y,都是 Double 类型。

结构体的定义包括以下几个部分:

  1. 结构体名称:在 struct 关键字后面的是结构体的名称,在这个例子中是 Point。结构体的名称通常以大写字母开头,遵循驼峰命名法。

  2. 属性:在大括号 {} 中定义结构体的属性。每个属性都有一个名称和一个类型。在这个例子中,Point 结构体有两个属性:x 和 y,它们的类型都是 Double。

  3. 变量或常量:结构体的属性可以是变量(使用 var 关键字定义)或常量(使用 let 关键字定义)。在这个例子中,x 和 y 都是变量,这意味着你可以改变它们的值。

实例化

在 Swift 中,一旦你定义了一个结构体,你就可以创建该结构体的实例。实例化结构体时,需要为其所有属性提供初始值。

以下是如何实例化 Point 结构体的示例:

var point = Point(x: 10.0, y: 20.0)

在这个例子中,我们创建了一个 Point 结构体的实例,并为 x 和 y 属性分别赋值了 10.0 和 20.0。

这里的 Point(x: 10.0, y: 20.0) 就是使用 Point 结构体的成员逐一构造器(memberwise initializer)创建的新实例。成员逐一构造器是 Swift 自动为所有结构体提供的一个特殊构造器,它的参数与结构体的属性一一对应。

创建的 point 实例是一个具有 x 和 y 属性的 Point 结构体。你可以通过点语法访问或修改这些属性的值,如 point.x 或 point.y。

值类型

在 Swift 中,结构体是值类型。这意味着当结构体的实例被赋值给新的变量或常量,或者被传递给函数时,其值会被复制。这与引用类型(如类)不同,引用类型在赋值或传递时,不会复制其值,而是共享同一个引用。

以下是一个示例,说明结构体是值类型:

struct Point {
    var x: Double
    var y: Double
}

var point1 = Point(x: 10.0, y: 20.0)
var point2 = point1  // 复制 point1 的值

point2.x = 30.0  // 修改 point2 的 x 属性

print(point1.x)  // 输出:10.0
print(point2.x)  // 输出:30.0

在这个例子中,我们首先创建了一个 Point 结构体的实例 point1,然后将 point1 的值复制给 point2。然后我们修改了 point2 的 x 属性。由于结构体是值类型,所以 point1 的 x 属性的值并没有改变,它仍然是 10.0。

这种特性使得结构体在处理不需要共享状态的数据时非常有用。你可以安全地传递结构体的实例,而不用担心其值会被意外修改。

方法

在 Swift 中,结构体可以定义方法。方法是与某个特定类型相关联的函数。你可以在结构体中定义方法,以提供与该类型相关的功能。

例如,以下代码在 Point 结构体中定义了一个名为 distance(to:) 的方法,它计算并返回当前点到另一个点的距离。

struct Point {
    var x: Double
    var y: Double

    func distance(to other: Point) -> Double {
        let dx = x - other.x
        let dy = y - other.y
        return sqrt(dx * dx + dy * dy)
    }
}

在这个例子中,我们在 Point 结构体中定义了一个名为 distance(to:) 的方法。这个方法接受一个 Point 类型的参数 other,并返回两点之间的距离。

你可以像下面这样调用结构体的方法:

let point1 = Point(x: 0.0, y: 0.0)
let point2 = Point(x: 10.0, y: 10.0)
let distance = point1.distance(to: point2)

在这个例子中,我们首先创建了两个 Point 结构体的实例 point1 和 point2,然后调用 point1 的 distance(to:) 方法,计算 point1 到 point2 的距离。

请注意,结构体的方法可以访问和修改结构体的属性。如果你需要在方法中修改结构体的属性,你需要将方法标记为 mutating。例如:

struct Point {
    var x: Double
    var y: Double

    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}

在这个例子中,moveBy(x:y:) 方法是一个 mutating 方法,它可以修改 Point 结构体的 x 和 y 属性。

可变性

在 Swift 中,结构体是值类型,这意味着当它的实例被赋值给新的变量或常量,或者被传递给函数时,其值会被复制。这种特性影响了结构体的可变性。

如果你将结构体的实例赋值给一个变量,你可以修改该实例的属性。但如果你将结构体的实例赋值给一个常量,你不能修改该实例的属性。这是因为结构体是值类型,当它被赋值给常量时,其值就不能再改变了。

以下是一个示例:

struct Point {
    var x: Double
    var y: Double
}

var point1 = Point(x: 10.0, y: 20.0)  // point1 是变量
point1.x = 30.0  // 可以修改 point1 的 x 属性

let point2 = Point(x: 10.0, y: 20.0)  // point2 是常量
point2.x = 30.0  // 错误:不能修改 point2 的 x 属性

在这个例子中,point1 是一个变量,所以我们可以修改它的 x 属性。但 point2 是一个常量,所以我们不能修改它的 x 属性。

扩展

你可以使用扩展(extensions)来添加新的功能到已存在的结构体类型。这包括添加新的方法和计算属性,定义和使用新的嵌套类型,以及使一个已存在的类型符合某个协议。

在 Swift 中,你可以使用扩展(extensions)来添加新的功能到已存在的结构体类型。扩展可以添加新的计算属性、实例方法、类型方法、初始化方法、下标、嵌套类型,以及使一个已存在的类型符合某个协议。

以下是一个在结构体上使用扩展的示例:

struct Point {
    var x: Double
    var y: Double
}

extension Point {
    func distance(to other: Point) -> Double {
        let dx = x - other.x
        let dy = y - other.y
        return sqrt(dx * dx + dy * dy)
    }
}

在这个例子中,我们首先定义了一个 Point 结构体,然后使用扩展添加了一个 distance(to:) 方法。这个方法计算并返回当前点到另一个点的距离。

请注意,扩展不能添加存储属性,也不能重写已存在的功能。扩展只能添加新的计算属性和方法,或者使一个已存在的类型符合某个协议。

此外,如果你需要在扩展的方法中修改结构体的属性,你需要将方法标记为 mutating。例如:

extension Point {
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}

协议

在 Swift 中,协议是定义了一些方法、属性或其他要求的蓝图。结构体可以遵循(conform)一个或多个协议(protocols),并提供这些协议所要求的实现。通过遵循协议,结构体可以保证提供某些特定的功能或行为。

以下是一个结构体遵循协议的示例:

protocol Movable {
    mutating func moveBy(x deltaX: Double, y deltaY: Double)
}

struct Point: Movable {
    var x: Double
    var y: Double

    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}

在这个例子中,我们首先定义了一个 Movable 协议,这个协议要求遵循它的类型实现一个 moveBy(x:y:) 方法。然后我们定义了一个 Point 结构体,并让它遵循 Movable 协议。Point 结构体提供了 moveBy(x:y:) 方法的实现,满足了 Movable 协议的要求。

通过遵循协议,结构体可以保证提供某些特定的功能或行为。这使得你可以在不同的类型之间共享行为,或者定义一些可以在多个类型之间通用的方法。

请注意,如果协议中的方法需要修改结构体的属性,你需要将这个方法标记为 mutating。在上面的例子中,Movable 协议中的 moveBy(x:y:) 方法就是 mutating 的,因为它需要修改 x 和 y 属性的值。

总结

结构体是 Swift 中非常重要的一部分,它们在构建复杂的数据模型时非常有用。结构体是值类型,这使得你可以安全地传递它们的实例,而不用担心其值会被意外修改。结构体可以定义方法,这些方法可以访问和修改结构体的属性。结构体还可以遵循协议,这使得你可以在不同的类型之间共享行为,或者定义一些可以在多个类型之间通用的方法。

通过理解和掌握这些知识点,你可以更有效地使用 Swift 结构体,编写出更优雅、更强大的代码。