玩Swift,来自Java背景,为什么要选择Struct而不是Class?看起来它们是一样的东西,只不过Struct提供的功能更少。那为什么选择它呢?


当前回答

一些好处:

由于不可共享,自动线程安全 由于没有isa和refcount,使用更少的内存(实际上通常是堆栈分配) 方法总是静态分派的,所以可以内联(尽管@final可以为类这样做) 更容易推理(不需要“防御性复制”,这是典型的NSArray, NSString等…)出于与线程安全相同的原因

其他回答

以下是一些值得考虑的其他原因:

struct有一个自动初始化式,你根本不需要在代码中维护它。 struct MorphProperty { var类型:MorphPropertyValueType var键:字符串 var值:AnyObject enum MorphPropertyValueType { case字符串,Int, Double } } var m = MorphProperty(类型:.Int,键:“什么”,值:“blah”)

要在类中得到这个,你必须添加初始化式,并维护初始化式…

Basic collection types like Array are structs. The more you use them in your own code, the more you will get used to passing by value as opposed to reference. For instance: func removeLast(var array:[String]) { array.removeLast() println(array) // [one, two] } var someArray = ["one", "two", "three"] removeLast(someArray) println(someArray) // [one, two, three] Apparently immutability vs. mutability is a huge topic, but a lot of smart folks think immutability -- structs in this case -- is preferable. Mutable vs immutable objects

对于类,您获得继承并通过引用传递,而结构则没有继承并通过值传递。

有很多关于Swift的WWDC会议,其中一个会议详细回答了这个问题。确保你看了这些,因为它会让你更快地跟上语言指南或iBook。

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

创建型模式:

在swift中,Struct是一种自动克隆的值类型。因此,我们可以免费获得实现原型模式所需的行为。

而类是引用类型,在赋值过程中不会自动克隆。为了实现原型模式,类必须采用NSCopying协议。


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


为每种引用类型实现深度复制已成为一项乏味的任务。如果类包含进一步的引用类型,我们必须为每个引用属性实现原型模式。然后我们需要通过实现NSCopying协议复制整个对象图。

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

class Address{
   var street:String
   ...
} 

通过使用结构体和枚举,我们使我们的代码更简单,因为我们不需要实现复制逻辑。

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

如果你不知道值类型和引用类型是什么,那么看看按引用传递和按值传递之间的区别是什么?

根据mikeash的帖子:

... Let's look at some extreme, obvious examples first. Integers are obviously copyable. They should be value types. Network sockets can't be sensibly copied. They should be reference types. Points, as in x, y pairs, are copyable. They should be value types. A controller that represents a disk can't be sensibly copied. That should be a reference type. Some types can be copied but it may not be something you want to happen all the time. This suggests that they should be reference types. For example, a button on the screen can conceptually be copied. The copy will not be quite identical to the original. A click on the copy will not activate the original. The copy will not occupy the same location on the screen. If you pass the button around or put it into a new variable you'll probably want to refer to the original button, and you'd only want to make a copy when it's explicitly requested. That means that your button type should be a reference type. View and window controllers are a similar example. They might be copyable, conceivably, but it's almost never what you'd want to do. They should be reference types. What about model types? You might have a User type representing a user on your system, or a Crime type representing an action taken by a User. These are pretty copyable, so they should probably be value types. However, you probably want updates to a User's Crime made in one place in your program to be visible to other parts of the program. This suggests that your Users should be managed by some sort of user controller which would be a reference type. e.g struct User {} class UserController { var users: [User] func add(user: User) { ... } func remove(userNamed: String) { ... } func ... } Collections are an interesting case. These include things like arrays and dictionaries, as well as strings. Are they copyable? Obviously. Is copying something you want to happen easily and often? That's less clear. Most languages say "no" to this and make their collections reference types. This is true in Objective-C and Java and Python and JavaScript and almost every other language I can think of. (One major exception is C++ with STL collection types, but C++ is the raving lunatic of the language world which does everything strangely.) Swift said "yes," which means that types like Array and Dictionary and String are structs rather than classes. They get copied on assignment, and on passing them as parameters. This is an entirely sensible choice as long as the copy is cheap, which Swift tries very hard to accomplish. ...

我个人不会这样命名我的类。我通常将我的命名为UserManager而不是UserController,但想法是一样的

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

所以不是一个类的几个子类。使用几个符合协议的结构体。


使用结构体的另一种合理情况是,当你想对新旧模型进行delta/diff运算时。对于引用类型,你不能开箱即用。对于值类型,突变是不共享的。

在这些回答中没有注意到的一点是,持有类和结构的变量可以是let,同时仍然允许对对象的属性进行更改,而对于结构则不能这样做。

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