玩Swift,来自Java背景,为什么要选择Struct而不是Class?看起来它们是一样的东西,只不过Struct提供的功能更少。那为什么选择它呢?
当前回答
我不会说结构体提供的功能更少。
当然,self是不可变的,除了在突变函数中,但仅此而已。
继承可以很好地工作,只要您坚持每个类都应该是抽象的或最终的。
将抽象类实现为协议,将最终类实现为结构。
struct的好处是你可以在不创建共享可变状态的情况下使你的字段可变,因为写时复制会照顾到这一点:)
这就是为什么下面例子中的属性/字段都是可变的,我不会在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)")
}
其他回答
一些好处:
由于不可共享,自动线程安全 由于没有isa和refcount,使用更少的内存(实际上通常是堆栈分配) 方法总是静态分派的,所以可以内联(尽管@final可以为类这样做) 更容易推理(不需要“防御性复制”,这是典型的NSArray, NSString等…)出于与线程安全相同的原因
对于类,您获得继承并通过引用传递,而结构则没有继承并通过值传递。
有很多关于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有一个自动初始化式,你根本不需要在代码中维护它。 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
结构比类快得多。同样,如果你需要继承,那么你必须使用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的实际实例是传递而不是引用(值类型)。
推荐文章
- 如何停止不必要的UIButton动画标题变化?
- 如何使用Swift播放声音?
- 如何解散ViewController在Swift?
- 保存字符串到NSUserDefaults?
- 如何将JSON字符串转换为字典?
- 什么是NSLocalizedString等效在Swift?
- 如何创建一个字符串的格式?
- 获取最顶端的UIViewController
- 使用isKindOfClass与Swift
- SourceKitService终止
- 在TypeScript / Angular中什么时候使用Interface和Model
- 我如何在Swift中解析/创建一个以分数秒UTC时区(ISO 8601, RFC 3339)格式化的日期时间戳?
- 如何使用@Binding变量实现自定义初始化
- Swift设置为Array
- 如何设置回退按钮文本在Swift