Struct和Class之间的区别
与许多其他编程语言相比,结构在Swift中非常强大。因此,应该更频繁地使用它们。
提示:这篇文章使用的是Swift 5
相似之处
首先,让我们开始讨论结构和类之间的相似性。它们实际上有很多共同点:
- 他们有方法和初始化器
- 他们已经存储和计算属性
- 他们可以扩展
- 他们可以实施协议
使用这些功能的方式有些差异,但是这些差异很小,不是本文的主要内容。例如,结构的初始化器是自动创建的,而对于类,则必须手动创建。
差异性
结构和类之间存在三个主要区别:
- 结构是值类型,而类是引用类型。
- 可以继承类。这对于结构是不可能的。
- 结构的Objective-C互操作性很差,而类则非常好。
让我们详细看看这些差异。
值类型与引用类型
那么值类型和引用类型之间有什么区别?引用类型的实例不能直接访问,只能通过使用所谓的引用来访问。因此,乘法引用可以指向同一实例。看下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class TestClassA {
var a: Int
init(a: Int) {
self.a = a
}
}
let testA = TestClassA(a: 5)
let testB = testA
print(testA.a) //5
print(testB.a) //5
testA.a = 10
print(testA.a) //10
print(testB.a) //10
|
如您所见,仅创建了一个TestClassA实例,但是有两个引用指向该实例。如果您更改的属性一的种皮,同样的情况对TESTB,因为它是相同的实例。

现在让我们看一个结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
struct TestStruct {
var a: Int
}
var testC = TestStruct(a: 5)
var testD = testC
print(testC.a) //5
print(testD.a) //5
testC.a = 10
print(testC.a) //10
print(testD.a) //5
|
同样,我们有两个值(testC和testD)。如果一个值的属性被更改,则另一个值不会发生这种情况,因为它不是同一实例。

还要注意,必须使用关键字var将testC和testD声明为变量。如果结构本身是常数,则无法更改结构的属性。
它与某些Swift类型(例如Int,String和Array)完全相同-它们也是值类型。但不仅如此,它们也是结构!
上面带有Int值的示例的相应示例:
1
2
3
4
5
6
7
8
9
10
|
var testE = 5
var testF = testE
print(testE) //5
print(testF) //5
testE = 10
print(testE) //10
print(testF) //5
|
如果您还没有使用过结构,那么最后一个示例对您来说可能自然得多。只是要提醒自己,由于Int 是结构,因此结构就像Int值一样工作。
引用类型和值类型的行为完全不同。假设您有一个引用类型的实例,并且在您的应用程序中有多个指向它的引用。如果使用这些引用之一更改值,则所有这些引用都指向相同的新值。这可能是通缉的行为。但是,如果不是这样,则可能是主要错误的来源。
由于值和引用类型之间的差异,因此内存管理也大不相同。最重要的一点是,引用类型可能会发生所谓的保留周期。对于值类型,这是不可能的。
Objective-C互操作性
Swift中的结构没有良好的Objective-C互操作性。如果在Swift中定义结构,则无法将其公开给Objective-C源代码。例如,这意味着UITableView的委托或数据源必须不是结构而是类,因为UIKit仍然是用Objective-C编写的。这听起来像是一个主要障碍,但实际上,这些情况比您想像的要少。
遗产
简而言之:结构没有继承。但是,还有其他方法可以为结构实现类似的行为。最常见的方法是使用协议。
默认使用结构
因此,一般准则是默认情况下应构造结构。原因是它们更易于使用和安全:保留周期不会发生,并且您无法偶然更改应用程序其他部分的值。
仅当您需要类特定的功能(例如继承,Objective-C互操作性)或想要引用类型的特定行为时,才应使用类。