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


当前回答

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

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

其他回答

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

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

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

当然,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)")
}

从值类型和引用类型的角度来回答这个问题,从苹果博客的这篇文章来看,它看起来非常简单:

使用值类型[例如struct, enum]: 用==比较实例数据是有意义的 你希望副本有独立的状态 这些数据将在代码中跨多个线程使用 在以下情况下使用引用类型[例如class]: 比较实例标识和===是有意义的 您希望创建共享的、可变的状态

正如在那篇文章中提到的,没有可写属性的类将与结构体的行为相同,但有一点需要注意:结构体最适合线程安全模型——这是现代应用程序架构中日益迫切的需求。

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

创建型模式:

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

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


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


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

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

class Address{
   var street:String
   ...
} 

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

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

我用简单的例子来创建主旨。 https://github.com/objc-swift/swift-classes-vs-structures

和差异

1. 继承。

结构不能在swift中继承。如果你愿意

class Vehicle{
}

class Car : Vehicle{
}

参加一个培训班。

2. 经过

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

语境的差异

结构常量和变量

示例(用于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代替,这是一个有效的表达式。因为在一个类中,不可变常量是对类本身的引用,而不是它的实例变量(除非那些变量定义为常量)