一尘不染

为什么要选择结构而非类?

swift

在Java背景下玩Swift,为什么要选择Struct而不是Class?似乎它们是同一回事,但Struct提供的功能较少。为什么选择它呢?


阅读 350

收藏
2020-07-07

共1个答案

一尘不染

根据非常流行的WWDC 2015演讲《
Swift中的面向协议的编程》(视频成绩单),Swift提供了许多功能,这些功能在许多情况下都比类更好。

如果结构相对较小且可复制,则结构是可取的,因为与在类中多次引用相同实例相比,复制要安全得多。当将变量传递给许多类和/或在多线程环境中时,这一点尤其重要。如果您始终可以将变量的副本发送到其他位置,则不必担心其他位置会更改您下面的变量的值。

使用Structs,无需担心内存泄漏或多个线程争夺访问/修改变量的单个实例的麻烦。(从更专业的角度来说,例外是在闭包内部捕获结构时,因为它实际上是在捕获对实例的引用,除非您明确地将其标记为要复制)。

类也可能变得肿,因为类只能从单个超类继承。这鼓励我们创建巨大的超类,其中包含松散相关的许多不同能力。使用协议,尤其是协议扩展,可以在其中提供协议的实现,可以消除类对实现此类行为的需要。

演讲列出了首选班级的这些情况:

  • 复制或比较实例没有意义(例如Window)
  • 实例的生存期与外部影响(例如TemporaryFile)有关
  • 实例只是“接收器”-到外部状态(例如CGContext)的只写管道

这意味着结构应该是默认值,而类应该是后备值。

另一方面,Swift编程语言文档有些矛盾:

结构实例始终按值传递,而类实例始终按引用传递。这意味着它们适合于各种任务。在考虑项目所需的数据结构和功能时,请确定是将每个数据结构定义为类还是结构。

作为一般准则,请考虑在以下一个或多个条件适用时创建结构:

  • 该结构的主要目的是封装一些相对简单的数据值。
  • 合理地预期,当您分配或传递该结构的实例时,将复制而不是引用封装的值。
  • 结构存储的任何属性本身都是值类型,也应该期望将其复制而不是引用。
  • 该结构不需要从另一个现有类型继承属性或行为。

良好的结构候选人包括:

  • 尺寸均为Double的几何形状的大小,可能封装了width属性和height属性。
  • 一种引用系列中范围的方法,可能封装了Int类型的start属性和length属性。
  • 3D坐标系中的一个点,可能封装了x,y和z属性,每个属性均为Double类型。

在所有其他情况下,请定义一个类,然后创建该类的实例以通过引用进行管理和传递。实际上,这意味着大多数自定义数据构造应该是类,而不是结构。

在这里,我们声称我们应该默认仅在特定情况下使用类和结构。最终,您需要了解值类型与引用类型的真实含义,然后可以就何时使用结构或类做出明智的决定。另外,请记住,这些概念一直在发展,并且在进行面向协议的编程演讲之前编写了Swift编程语言文档。

2020-07-07