使用 Swift,来自 Java 背景,为什么要选择 Struct 而不是 Class?似乎它们是相同的东西,结构提供的功能较少。那为什么选择它?
根据非常流行的 WWDC 2015 演讲 Protocol Oriented Programming in Swift(视频、脚本),Swift 提供了许多特性,使结构在许多情况下优于类。
如果结构相对较小且可复制,则结构更可取,因为复制比使用类对同一实例进行多个引用更安全。当将变量传递给许多类和/或在多线程环境中时,这一点尤其重要。如果您始终可以将变量的副本发送到其他地方,那么您永远不必担心其他地方会更改您下面的变量的值。
使用 Structs,不必担心内存泄漏或多个线程竞相访问/修改变量的单个实例。(对于更有技术头脑的人来说,例外情况是在闭包内捕获结构时,因为它实际上是在捕获对实例的引用,除非您明确将其标记为要复制)。
类也可能变得臃肿,因为一个类只能从一个超类继承。这鼓励我们创建巨大的超类,其中包含许多只是松散相关的不同能力。使用协议,尤其是可以提供协议实现的协议扩展,可以让您消除对实现此类行为的类的需求。
该演讲列出了首选类的这些场景:
复制或比较实例没有意义(例如,Window) 实例生命周期与外部影响相关(例如,TemporaryFile) 实例只是“sinks”——到外部状态的只写管道(egCGContext)
这意味着结构应该是默认的,类应该是后备的。
另一方面,Swift 编程语言文档有些矛盾:
结构实例总是按值传递,类实例总是按引用传递。这意味着它们适用于不同类型的任务。当您考虑项目所需的数据结构和功能时,请决定是否应将每个数据结构定义为类或结构。 作为一般准则,请考虑在以下一个或多个条件适用时创建结构: 该结构的主要目的是封装一些相对简单的数据值。 当您分配或传递该结构的实例时,期望封装的值将被复制而不是引用是合理的。 结构存储的任何属性本身都是值类型,也应该被复制而不是引用。 该结构不需要从另一个现有类型继承属性或行为。 结构的良好候选示例包括: 几何形状的大小,可能封装了宽度属性和高度属性,都是 Double 类型。 一种引用系列中范围的方法,可能封装了 Int 类型的 start 属性和 length 属性。 3D 坐标系中的一个点,可能封装了 x、y 和 z 属性,每个属性都是 Double 类型。 在所有其他情况下,定义一个类,并创建该类的实例以通过引用进行管理和传递。实际上,这意味着大多数自定义数据结构应该是类,而不是结构。
结构实例总是按值传递,类实例总是按引用传递。这意味着它们适用于不同类型的任务。当您考虑项目所需的数据结构和功能时,请决定是否应将每个数据结构定义为类或结构。
作为一般准则,请考虑在以下一个或多个条件适用时创建结构:
结构的良好候选示例包括:
在所有其他情况下,定义一个类,并创建该类的实例以通过引用进行管理和传递。实际上,这意味着大多数自定义数据结构应该是类,而不是结构。
这里声称我们应该默认使用类并仅在特定情况下使用结构。最终,您需要了解值类型与引用类型在现实世界中的含义,然后您可以就何时使用结构或类做出明智的决定。另外,请记住,这些概念一直在发展,并且 Swift 编程语言文档是在面向协议编程演讲之前编写的。