为什么要选择结构而不是课程?


476

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


11
结构在您的代码中传递时总是被复制,并且不使用引用计数。来源:developer.apple.com/library/prerelease/ios/documentation/swift/...
holex

4
我会说结构更适合保存数据,而不是逻辑。用Java术语来说,将结构想象为“值对象”。
Vincent Guerci 2014年

6
在整个对话中,我感到很惊讶,没有直接提到写时复制又称惰性复制。由于这种设计,对结构复制性能的任何担忧都几乎没有意义。
戴维·詹姆斯

3
选择一个类的结构不是意见问题。选择其中一个是有特定原因的。
大卫·詹姆斯

我强烈建议您查看Array为什么不是threadSafe。这是相关的,因为数组和结构都是值类型。这里的所有答案都提到,使用structs / arrays / value类型永远不会出现线程安全问题,但是您会遇到一个极端的情况。
亲爱的

Answers:


548

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

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

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

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

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

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

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

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

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

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

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

良好的结构候选人包括:

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

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

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


11
@ElgsQianChen本文的重点是默认情况下应选择struct,仅在必要时使用class。结构更加安全且无漏洞,尤其是在多线程环境中。是的,您始终可以使用类代替结构,但最好使用结构。
drewag

16
@drewag这似乎与它所说的完全相反。有人说,类应该是您使用的默认值,而不是结构In practice, this means that most custom data constructs should be classes, not structures.。您可以向我解释一下,读完之后如何得到大多数数据集应该是结构而不是类?当某些东西应该是一个结构时,他们给出了一套特定的规则,并且几乎说“在所有其他情况下,一个班级会更好”。
马特

42
最后一行应该说:“我的个人建议与文档相反:” ...然后这是一个很好的答案!
Dan Rosenstark

5
Swift 2.2书仍然说在大多数情况下使用类。
戴维·詹姆斯

6
在类上构造绝对可以降低复杂性。但是当struct成为默认选择时,对内存使用的影响是什么。当事物被复制到各处而不是被引用时,应会增加应用程序的内存使用量。不是吗
MadNik '16

164

由于struct实例是在堆栈上分配的,而class实例是在堆上分配的,因此结构有时有时会更快。

但是,您应该始终自己进行测量,并根据您的独特用例进行决策。

考虑以下示例,该示例演示了Int使用struct和包装数据类型的2种策略class。我使用10个重复值是为了更好地反映您具有多个字段的真实世界。

class Int10Class {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

struct Int10Struct {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

func + (x: Int10Class, y: Int10Class) -> Int10Class {
    return IntClass(x.value + y.value)
}

func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
    return IntStruct(x.value + y.value)
}

性能使用

// Measure Int10Class
measure("class (10 fields)") {
    var x = Int10Class(0)
    for _ in 1...10000000 {
        x = x + Int10Class(1)
    }
}

// Measure Int10Struct
measure("struct (10 fields)") {
    var y = Int10Struct(0)
    for _ in 1...10000000 {
        y = y + Int10Struct(1)
    }
}

func measure(name: String, @noescape block: () -> ()) {
    let t0 = CACurrentMediaTime()

    block()

    let dt = CACurrentMediaTime() - t0
    print("\(name) -> \(dt)")
}

可以在https://github.com/knguyen2708/StructVsClassPerformance中找到代码

更新(2018年3月27日)

从Swift 4.0(Xcode 9.2)开始,在iPhone 6S,iOS 11.2.6上运行Release build,Swift Compiler设置为-O -whole-module-optimization

  • class 版本花费了2.06秒
  • struct 版本花费了4.17e-08秒(快了50,000,000倍)

(我不再对多次运行进行平均,因为方差很小,不到5%)

注意:如果不对整个模块进行优化,则差异不大。如果有人能指出该旗标的实际作用,我将感到非常高兴。


更新(2016年5月7日)

从Swift 2.2.1,Xcode 7.3开始,在iPhone 6S,iOS 9.3.1上运行Release版本,平均运行5次以上,Swift Compiler设置为-O -whole-module-optimization

  • class 版本花了2.159942142s
  • struct 版本花费了5.83E-08s(快了37,000,000倍)

注意:正如有人提到的那样,在实际情况下,结构中可能会有1个以上的字段,我为具有10个字段而不是1个字段的结构/类添加了测试。令人惊讶的是,结果差别不大。


原始结果(2014年6月1日):

(对结构/类使用1个字段,而不是10个)

从Swift 1.2,Xcode 6.3.2开始,在iPhone 5S,iOS 8.3上运行Release版本,平均运行5次

  • class 版本花费了9.788332333s
  • struct 版本花费了0.010532942s(速度提高了900倍)

旧结果(来自未知时间)

(对结构/类使用1个字段,而不是10个)

在我的MacBook Pro上发布版本:

  • class版本了1.10082秒
  • struct版本耗时0.02324秒(快50倍)

27
没错,但是似乎复制一堆结构比复制对单个对象的引用要慢。换句话说,复制单个指针比复制任意大的内存块要快。
Tylerc230

14
-1此测试不是一个很好的示例,因为该结构上只有一个var。请注意,如果添加多个值和一个或两个对象,则结构版本将与类版本相当。您添加的变量越多,结构版本越慢。
joshrl 2015年

6
@joshrl是您的意思,但是一个例子是“好”还是不取决于具体情况。此代码是从我自己的应用程序中提取的,因此这是一个有效的用例,使用结构确实极大地提高了我的应用程序的性能。这可能不是一个常见的用例(嗯,对于大多数应用程序来说,常见的用例是没有人关心数据的传输速度如何,因为瓶颈发生在其他地方,例如网络连接,无论如何,优化并不是那样。当您拥有配备GB或RAM的GHz设备时至关重要。
Khanh Nguyen

26
据我了解,快速复制已优化为在WRITE时进行。这意味着除非要更改新副本,否则不会进行物理内存副本。
Matjan '16

6
这个答案显示了一个极其琐碎的例子,以至于不切实际,因此在许多情况下都是错误的。更好的答案是“取决于情况”。
iwasrobbed '16

60

结构和类之间的相似之处。

我通过简单的示例为此创建了要点。 https://github.com/objc-swift/swift-classes-vs-structures

和差异

1.继承。

结构不能快速继承。如果你想

class Vehicle{
}

class Car : Vehicle{
}

去上课。

2.路过

Swift结构按值传递,而类实例按引用传递。

语境差异

结构常量和变量

示例(在WWDC 2014上使用)

struct Point{

   var x = 0.0;
   var y = 0.0;

} 

定义一个称为Point的结构。

var point = Point(x:0.0,y:2.0)

现在,如果我尝试更改x。它是一个有效的表达式。

point.x = 5

但是,如果我将点定义为常数。

let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.

在这种情况下,整个点是不变的常数。

如果我使用Point类,则这是一个有效的表达式。因为在类中,不可变常量是对类本身的引用,而不是对其实例变量的引用(除非那些变量定义为常量)



12
上面的要点是关于如何实现struct的继承风格。您将看到类似的语法。答:B。它是称为A的结构,实现了称为B的协议。Apple文档明确提到该结构不支持纯继承,但不支持纯继承。
MadNik

2
男人,你的最后一段很棒。我一直都知道您可以更改常量...但是有时我会发现您无法更改常量,所以我感到困惑。这种区别显而易见
亲爱的,

28

还有其他一些要考虑的原因:

  1. structs获得了一个自动初始化程序,您根本不必在代码中进行维护。

    struct MorphProperty {
       var type : MorphPropertyValueType
       var key : String
       var value : AnyObject
    
       enum MorphPropertyValueType {
           case String, Int, Double
       }
     }
    
     var m = MorphProperty(type: .Int, key: "what", value: "blah")

为了在一个类中做到这一点,您必须添加初始化程序,并维护初始化程序。

  1. 基本的集合类型如Array结构。您在自己的代码中使用它们的次数越多,您就会习惯于按值传递而不是引用。例如:

    func removeLast(var array:[String]) {
       array.removeLast()
       println(array) // [one, two]
    }
    
    var someArray = ["one", "two", "three"]
    removeLast(someArray)
    println(someArray) // [one, two, three]
  2. 显然,不变性与可变性是一个巨大的话题,但是许多聪明人认为,不变性(在这种情况下为结构)是更可取的。可变对象与不可变对象


4
的确,您会获得自动初始化程序。当所有属性均为Optional时,您还将获得一个空的初始化程序。但是,如果您在Framework中有一个结构,那么如果希望在internal范围外使用它,则需要自己实际编写该初始化程序。
阿比森

2
@Abizern证实- stackoverflow.com/a/26224873/8047 -这就是男人和烦人。
Dan Rosenstark '16

2
@Abizern在Swift中进行所有操作都有很大的理由,但是每次在某个地方而不是在另一个地方都是正确的事情时,开发人员就必须了解更多的知识。我猜这是我应该说的地方:“以如此具有挑战性的语言工作真是令人兴奋!”
Dan Rosenstark '16年

4
我还可以补充一点,不是结构的不变性才使它们有用(尽管这是一件非常好的事情)。您可以mutating更改结构,但是必须将方法标记为,这样您就可以清楚了解哪些函数会更改其状态。但是它们作为值类型的性质很重要。如果声明一个结构体,let则不能对其调用任何变异函数。关于通过值类型更好地编程的WWDC 15视频是一个很好的资源。
阿比森

1
感谢@Abizern,在阅读您的评论之前,我从未真正理解过此内容。对于对象,let vs. var并没有太大的区别,但是对于结构而言,它是巨大的。感谢您指出了这一点。
Dan Rosenstark '16

27

假设我们知道Struct是一个值类型,Class是一个引用类型

如果您不知道值类型和引用类型是什么,请参阅按引用传递与按值传递有什么区别?

根据mikeash的帖子

...让我们先来看一些极端的,显而易见的例子。整数显然是可复制的。它们应该是值类型。无法明智地复制网络套接字。它们应该是引用类型。x,y对中的点是可复制的。它们应该是值类型。不能明智地复制代表磁盘的控制器。那应该是一个引用类型。

某些类型可以被复制,但可能并非您一直希望发生。这表明它们应该是引用类型。例如,可以从概念上复制屏幕上的按钮。该副本将与原始副本不太相同。单击副本将不会激活原件。该副本将不会在屏幕上占据相同的位置。如果您将按钮传递或放入新变量中,则可能要引用原始按钮,并且只希望在明确请求时进行复制。这意味着您的按钮类型应该是引用类型。

视图和窗口控制器是类似的示例。可以想象,它们可能是可复制的,但几乎从来都不是您想要做的。它们应该是引用类型。

型号类型呢?您可能具有代表系统上用户的“用户”类型,或代表用户采取的操作的“犯罪”类型。这些都是可复制的,因此它们应该是值类型。但是,您可能希望在程序的某个位置进行的用户犯罪更新对于程序的其他部分是可见的。 这表明您的用户应该由某种用户控制器来管理,这将是一个引用类型。例如

struct User {}
class UserController {
    var users: [User]

    func add(user: User) { ... }
    func remove(userNamed: String) { ... }
    func ...
}

收藏是一个有趣的案例。这些包括数组和字典之类的东西,以及字符串。它们可以复制吗?明显。复制想要轻松且经常发生的事情吗?这还不清楚。

大多数语言对此表示“否”,并使其集合引用类型。在Objective-C,Java,Python和JavaScript以及我能想到的几乎所有其他语言中都是如此。(一个主要的例外是具有STL集合类型的C ++,但是C ++是语言界疯狂的疯子,它奇怪地完成了所有工作。)

Swift说“是”,这意味着诸如Array和Dictionary和String之类的类型是结构而不是类。它们在分配时以及作为参数传递时被复制。只要副本便宜,这是完全明智的选择,Swift会非常努力地做到这一点。...

我个人不这样命名我的班级。我通常将其命名为UserManager而不是UserController,但想法是相同的

另外,当您必须覆盖函数的每个实例(即它们没有任何共享功能)时,请不要使用类。

因此,而不是拥有一个类的几个子类。使用符合协议的几种结构。


对于结构的另一种合理情况是,当您想对旧模型和新模型进行增量/差异处理时。对于引用类型,您不能开箱即用。对于值类型,不共享突变。


1
正是我想要的那种解释。尼斯写:)
androCoder-BD

非常有用的控制器示例
问P

1
@AskP我给迈克本人发了电子邮件,并获得了额外的代码:)
亲爱的

18

一些优点:

  • 由于不可共享而自动线程安全
  • 由于没有isa和refcount,因此使用较少的内存(实际上通常是堆栈分配的)
  • 方法总是静态分配的,因此可以进行内联(尽管@final可以对类执行此操作)
  • 出于与线程安全相同的原因,更易于推理(无需像NSArray,NSString等一般进行“防御性复制”)

不知道这是否超出此答案的范围,但是您能否解释(或链接,我想)“方法总是静态分配的”这一点?
Dan Rosenstark '16

2
当然。我也可以附加警告。动态分派的目的是在您不知道要使用哪个实现时选择一种实现。在Swift中,这可能是由于继承(可能在子类中重写),也可能是由于函数是通用的(您不知道通用参数是什么)。无法继承结构,并且整个模块优化+泛型专门化大都消除了未知的泛型,因此可以直接调用方法,而不必查找要调用的内容。非专业的泛型仍然可以对结构进行动态分配
Catfish_Man 16'Mar

1
谢谢,很好的解释。因此,我们期望更高的运行速度,或者从IDE的角度来看减少歧义,或者两者兼而有之?
Dan Rosenstark '16

1
主要是前者。
Catfish_Man

请注意,如果您通过协议引用该结构,则方法不会静态分配。
Cristik '18年

12

结构比Class快得多。另外,如果需要继承,则必须使用Class。最重要的一点是,Class是引用类型,而Structure是值类型。例如,

class Flight {
    var id:Int?
    var description:String?
    var destination:String?
    var airlines:String?
    init(){
        id = 100
        description = "first ever flight of Virgin Airlines"
        destination = "london"
        airlines = "Virgin Airlines"
    } 
}

struct Flight2 {
    var id:Int
    var description:String
    var destination:String
    var airlines:String  
}

现在让我们创建两者的实例。

var flightA = Flight()

var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )

现在让我们将这些实例传递给两个函数,这些函数可以修改ID,描述,目标等。

func modifyFlight(flight:Flight) -> Void {
    flight.id = 200
    flight.description = "second flight of Virgin Airlines"
    flight.destination = "new york"
    flight.airlines = "Virgin Airlines"
}

也,

func modifyFlight2(flight2: Flight2) -> Void {
    var passedFlight = flight2
    passedFlight.id = 200
    passedFlight.description = "second flight from virgin airlines" 
}

所以,

modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)

现在,如果我们打印flightA的ID和说明,我们将得到

id = 200
description = "second flight of Virgin Airlines"

在这里,我们可以看到FlightA的ID和说明已更改,因为传递给Modify方法的参数实际上指向flightA对象(引用类型)的内存地址。

现在,如果我们输出FLightB实例的ID和说明,

id = 100
description = "first ever flight of Virgin Airlines"

在这里我们可以看到FlightB实例没有更改,因为在ModifyFlight2方法中,Flight2的实际实例是传递而不是引用(值类型)。


2
您从未创建FLightB实例
David Seek

1
那你为什么要谈论FlightB兄弟?Here we can see that the FlightB instance is not changed
大卫·希克

@ManojKarki,好答案。我只是想指出,当我想声明FlightA,然后声明FlightB时,您两次声明了flightA。
ScottyBlades

11

Structsvalue typeClassesreference type

  • 值类型比引用类型快
  • 值类型实例在多线程环境中是安全的,因为多个线程可以更改实例而不必担心竞争条件或死锁
  • 与引用类型不同,值类型没有引用。因此没有内存泄漏。

在以下情况下使用value类型:

  • 您希望副本具有独立的状态,数据将在多个线程的代码中使用

在以下情况下使用reference类型:

  • 您要创建共享的可变状态。

进一步的信息也可以在Apple文档中找到

https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html


附加信息

Swift值类型保留在堆栈中。在一个进程中,每个线程都有其自己的堆栈空间,因此,其他线程将无法直接访问您的值类型。因此,没有竞争条件,锁,死锁或任何相关的线程同步复杂性。

值类型不需要动态内存分配或引用计数,这两者都是昂贵的操作。同时,值类型的方法是静态分派的。这些在性能方面为值类型提供了巨大的优势。

提醒一下,这里是Swift列表

值类型:

  • 结构
  • 枚举
  • 元组
  • 基本体(Int,Double,Bool等)
  • 集合(数组,字符串,字典,集合)

参考类型:

  • 任何来自NSObject的东西
  • 功能
  • 关闭

5

从值类型与引用类型的角度回答问题,在此Apple博客文章中,它看起来非常简单:

在以下情况下,请使用值类型[例如struct,enum]:

  • 将实例数据与==进行比较很有意义
  • 您希望副本具有独立状态
  • 数据将在多个线程的代码中使用

在以下情况下,请使用引用类型[例如类]:

  • 将实例身份与===进行比较比较有意义
  • 您要创建共享的可变状态

如该文章所述,没有可写属性的类的行为与结构相同,但有一个警告:(我要补充一点):结构最适合线程安全模型 -现代应用程序体系结构中日益迫切的需求。


3

对于类,您可以继承并通过引用传递,而结构不具有继承,而是通过值传递。

在Swift上有很棒的WWDC会议,其中一个具体问题得到了详细解答。确保您观看这些内容,因为它可以使您比语言指南或iBook更快地掌握速度。


您能否提供您提到的链接?WWDC上的原因有很多可供选择,我想观看一个谈论此特定主题的话题
MMachinegun 2015年

对我来说这是一个好的开始在这里:github.com/raywenderlich/...
MMachinegun

2
他可能正在谈论这个伟大的会议:Swift中的面向协议的编程。(链接:视频成绩单
zekel 2016年

2

我不会说结构提供较少的功能。

当然,除了可变功能之外,自我是不可变的,仅此而已。

只要您坚持每个类都应该是抽象类或最终类的好主意,继承就可以正常工作。

将抽象类实现为协议,将最终类实现为结构。

关于结构的好处是,您可以使字段可变而无需创建共享可变状态,因为写时复制可解决此问题:)

这就是以下示例中的属性/字段全部可变的原因,而我在Java或C#或swift 类中则不会这样做。

示例继承结构在名为“ example”的函数的底部带有一些肮脏而直接的用法:

protocol EventVisitor
{
    func visit(event: TimeEvent)
    func visit(event: StatusEvent)
}

protocol Event
{
    var ts: Int64 { get set }

    func accept(visitor: EventVisitor)
}

struct TimeEvent : Event
{
    var ts: Int64
    var time: Int64

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }
}

protocol StatusEventVisitor
{
    func visit(event: StatusLostStatusEvent)
    func visit(event: StatusChangedStatusEvent)
}

protocol StatusEvent : Event
{
    var deviceId: Int64 { get set }

    func accept(visitor: StatusEventVisitor)
}

struct StatusLostStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var reason: String

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

struct StatusChangedStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var newStatus: UInt32
    var oldStatus: UInt32

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

func readEvent(fd: Int) -> Event
{
    return TimeEvent(ts: 123, time: 56789)
}

func example()
{
    class Visitor : EventVisitor
    {
        var status: UInt32 = 3;

        func visit(event: TimeEvent)
        {
            print("A time event: \(event)")
        }

        func visit(event: StatusEvent)
        {
            print("A status event: \(event)")

            if let change = event as? StatusChangedStatusEvent
            {
                status = change.newStatus
            }
        }
    }

    let visitor = Visitor()

    readEvent(1).accept(visitor)

    print("status: \(visitor.status)")
}

2

在Swift中,引入了一种新的编程模式,称为面向协议的编程。

创作模式:

快速地,Struct是一个自动克隆的值类型。因此,我们获得了免费实现原型模式所需的行为。

是引用类型,在分配过程中不会自动将其克隆。要实现原型模式,类必须采用NSCopying协议。


浅拷贝复制指向这些对象的引用,而深拷贝则复制对象的引用。


为每种引用类型实现深拷贝已成为一项繁琐的任务。如果类包含其他引用类型,则必须为每个引用属性实现原型模式。然后,我们必须通过实现协议来实际复制整个对象图。NSCopying

class Contact{
  var firstName:String
  var lastName:String
  var workAddress:Address // Reference type
}

class Address{
   var street:String
   ...
} 

通过使用structs和enums,由于不必实现复制逻辑,我们使代码更简单。



0

在这些答案中没有引起注意的一点是,拥有类与结构的变量可能let仍然需要一段时间才能允许更改对象的属性,而您不能使用结构来进行更改。

如果您不希望变量指向另一个对象,但仍需要修改该对象,即在有许多实例变量希望一个接一个地更新的情况下,这很有用。如果它是一个结构体,则必须使用此方法将变量完全重置为另一个对象var,因为Swift中的常量值类型正确地允许零突变,而引用类型(类)则不这样。


0

由于struct是值类型,因此您可以非常容易地创建存储在堆栈中的内存.Struct可以轻松访问,并且在工作范围之后,可以很容易地从堆栈内存中通过弹出堆栈将其从内存中释放。另一方面,类是一个引用类型,它存储在堆中,并且在一个类对象中进行的更改会紧密地耦合到另一个对象,并且引用类型会影响其他对象。结构的所有成员都是公共的,而类的所有成员都是私有的。

struct的缺点是它不能被继承。


-7
  • 结构和类是用户定义的数据类型

  • 默认情况下,结构是公共的,而类是私有的

  • 类实现封装的原理

  • 类的对象在堆存储器上创建

  • 类用于可重用性,而结构用于将数据分组为同一结构

  • 结构数据成员不能直接初始化,但可以由结构外部分配

  • 类数据成员可以直接由参数less构造函数初始化,并由参数化构造函数分配


2
有史以来最差的答案!
J. Doe,

复制粘贴答案
limbadAli
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.