玩Swift,来自Java背景,为什么要选择Struct而不是Class?看起来它们是一样的东西,只不过Struct提供的功能更少。那为什么选择它呢?
当前回答
结构比类快得多。同样,如果你需要继承,那么你必须使用Class。最重要的一点是类是引用类型,而结构是值类型。例如,
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"
}
so,
modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)
现在如果我们打印航班a的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的实际实例是传递而不是引用(值类型)。
其他回答
一些好处:
由于不可共享,自动线程安全 由于没有isa和refcount,使用更少的内存(实际上通常是堆栈分配) 方法总是静态分派的,所以可以内联(尽管@final可以为类这样做) 更容易推理(不需要“防御性复制”,这是典型的NSArray, NSString等…)出于与线程安全相同的原因
许多Cocoa api需要NSObject子类,这迫使你使用class。但除此之外,你可以使用以下苹果Swift博客中的案例来决定是使用struct / enum值类型还是类引用类型。
https://developer.apple.com/swift/blog/?id=10
在这些回答中没有注意到的一点是,持有类和结构的变量可以是let,同时仍然允许对对象的属性进行更改,而对于结构则不能这样做。
如果你不希望变量指向另一个对象,但仍然需要修改对象,即在有许多实例变量的情况下,你希望一个接一个地更新,这是很有用的。如果它是一个结构,你必须允许变量被重置为另一个对象使用var,因为在Swift常量值类型正确地允许零突变,而引用类型(类)不这样做。
根据2015年非常流行的WWDC演讲,Swift中面向协议的编程(视频,文本),Swift提供了许多特性,使得结构在很多情况下比类更好。
如果结构相对较小且可复制,则更可取,因为复制比类中对同一个实例有多个引用要安全得多。当将一个变量传递给多个类和/或多线程环境时,这一点尤其重要。如果你总是可以将变量的副本发送到其他地方,你就不必担心其他地方会改变你下面变量的值。
使用Structs,不太需要担心内存泄漏或多个线程竞相访问/修改变量的单个实例。(对于更有技术头脑的人来说,例外情况是在闭包内捕获结构时,因为它实际上是在捕获实例的引用,除非您显式地将其标记为要复制)。
类也可能变得臃肿,因为一个类只能继承一个超类。这鼓励我们创建巨大的超类,其中包含许多不同的能力,而这些能力之间只有松散的关联。使用协议,特别是使用可以为协议提供实现的协议扩展,允许您消除实现此类行为所需的类。
演讲列出了优先使用类的这些场景:
复制或比较实例没有意义(例如,Window) 实例生命周期与外部效果(例如,TemporaryFile)相关联。 实例只是“接收器”——只写外部状态的管道(例如cgcontext)
这意味着结构应该是默认的,而类应该是备用的。
另一方面,Swift编程语言文档有些矛盾:
Structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks. As you consider the data constructs and functionality that you need for a project, decide whether each data construct should be defined as a class or as a structure. As a general guideline, consider creating a structure when one or more of these conditions apply: The structure’s primary purpose is to encapsulate a few relatively simple data values. It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure. Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced. The structure does not need to inherit properties or behavior from another existing type. Examples of good candidates for structures include: The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double. A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double. In all other cases, define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures.
在这里,它声称我们应该只在特定的情况下默认使用类和使用结构。最后,您需要了解值类型与引用类型的实际含义,然后才能就何时使用结构或类做出明智的决定。此外,请记住,这些概念一直在发展,Swift编程语言文档是在面向协议编程演讲之前编写的。
以下是一些值得考虑的其他原因:
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