563 Stimmen

Warum Struct anstelle von Klasse wählen?

Beim Spielen mit Swift, kommend aus einem Java-Hintergrund, warum sollte man sich für eine Struktur statt einer Klasse entscheiden? Es scheint, als ob sie dasselbe wären, wobei eine Struktur weniger Funktionalität bietet. Warum also wählen?

3voto

yeoman Punkte 1611

Ich würde nicht sagen, dass Strukturen weniger Funktionalität bieten.

Sicher, self ist unveränderlich, außer in einer mutating Funktion, aber das ist auch schon alles.

Vererbung funktioniert gut, solange man sich an die gute alte Idee hält, dass jede Klasse entweder abstrakt oder final sein sollte.

Implementieren Sie abstrakte Klassen als Protokolle und finale Klassen als Strukturen.

Das Schöne an Strukturen ist, dass Sie Ihre Felder veränderlich machen können, ohne gemeinsamen veränderlichen Zustand zu erzeugen, denn Copy-On-Write kümmert sich darum :)

Deshalb sind die Eigenschaften / Felder im folgenden Beispiel alle veränderlich, was ich in Java oder C# oder swift Klassen nicht machen würde.

Beispiel Vererbungsstruktur mit etwas schmutziger und direkter Verwendung unten in der Funktion "Beispiel":

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("Ein Zeitereignis: \(event)")
        }

        func visit(event: StatusEvent)
        {
            print("Ein Statusereignis: \(event)")

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

    let visitor = Visitor()

    readEvent(1).accept(visitor)

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

3voto

Joride Punkte 3712

Mit Klassen erhalten Sie Vererbung und werden per Referenz übergeben, Strukturen haben keine Vererbung und werden per Wert übergeben.

Es gibt großartige WWDC-Sitzungen zu Swift, diese spezifische Frage wird in einer von ihnen ausführlich beantwortet. Achten Sie darauf, diese anzusehen, da Sie dadurch viel schneller auf den neuesten Stand kommen als mit dem Sprachführer oder dem iBook.

3voto

Balasubramanian Punkte 4786

In Swift wurde ein neues Programmiermuster namens protokollorientiertes Programmieren eingeführt.

Erstellungsmuster:

In Swift, Struct ist ein Wertetyp, der automatisch geklont wird. Daher erhalten wir das erforderliche Verhalten, um das Prototypenmuster kostenlos zu implementieren.

Während Klassen der Referenztyp sind, die nicht automatisch beim Zuweisen geklont werden. Um das Prototypenmuster zu implementieren, müssen Klassen das NSCopying-Protokoll übernehmen.


Shallow Copy dupliziert nur die Referenz, die auf diese Objekte zeigt, während Deep Copy die Referenz des Objekts dupliziert.


Das Implementieren einer Deep Copy für jeden Referenztyp ist zu einer mühsamen Aufgabe geworden. Wenn Klassen weitere Referenztypen enthalten, müssen wir das Prototypenmuster für jede der referenzierten Eigenschaften implementieren. Und dann müssen wir tatsächlich den gesamten Objektgraphen kopieren, indem wir das NSCopying-Protokoll implementieren.

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

class Address{
   var street:String
   ...
} 

Durch die Verwendung von Strukturen und Enums haben wir unseren Code einfacher gemacht, da wir die Kopierlogik nicht implementieren müssen.

1voto

akshay Punkte 775

Viele Cocoa-APIs erfordern NSObject-Unterklassen, was Sie dazu zwingt, eine Klasse zu verwenden. Aber abgesehen davon können Sie die folgenden Fälle aus dem Apple Swift-Blog verwenden, um zu entscheiden, ob Sie einen struct / enum-Werttyp oder einen class-Referenztyp verwenden möchten.

https://developer.apple.com/swift/blog/?id=10

1voto

johnbakers Punkte 23574

Ein Punkt, der in diesen Antworten nicht beachtet wird, ist, dass eine Variable, die eine Klasse gegenüber einer Struktur hält, ein let sein kann, während immer noch Änderungen an den Eigenschaften des Objekts möglich sind, während dies bei einer Struktur nicht möglich ist.

Dies ist nützlich, wenn Sie nicht möchten, dass die Variable jemals auf ein anderes Objekt verweist, aber dennoch das Objekt ändern müssen, z.B. im Fall von vielen Instanzvariablen, die Sie nacheinander aktualisieren möchten. Wenn es sich um eine Struktur handelt, müssen Sie die Variable auf ein anderes Objekt zurücksetzen können, indem Sie var verwenden, um dies zu erreichen, da ein konstanter Werttyp in Swift nullmutation korrekt zulässt, während Verweistypen (Klassen) sich nicht auf diese Weise verhalten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X