568 Stimmen

Warum Struktur über Klasse wählen?

Beim Experimentieren mit Swift, kommend aus einer Java-Hintergrund, warum möchtest du eine Struktur anstelle einer Klasse wählen? Es scheint, dass sie dasselbe sind, wobei eine Struktur weniger Funktionalität bietet. Warum sollte man sie dann wählen?

13 Stimmen

Strukturen werden immer kopiert, wenn sie in Ihrem Code weitergereicht werden und verwenden kein Referenzzählen. Quelle: developer.apple.com/library/prerelease/ios/documentation/swi‌​ft/…

4 Stimmen

Ich würde sagen, dass structs besser geeignet sind, um Daten zu speichern, nicht Logik. Um es in Java-Begriffen auszudrücken, stelle dir structs als "Value Objects" vor.

6 Stimmen

Ich bin erstaunt, dass im gesamten Gespräch nicht direkt auf copy-on-write oder lazy copy verwiesen wird. Eventuelle Bedenken in Bezug auf die Leistung beim Strukturkopieren sind aufgrund dieses Designs größtenteils obsolet.

3voto

yeoman Punkte 1611

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

Sicher, self ist unveränderlich, außer in einer mutierenden Funktion, aber das war's dann auch schon.

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 Structs.

Das Gute an Structs ist, dass Sie Ihre Felder veränderbar machen können, ohne gemeinsamen veränderlichen Zustand zu erstellen, weil das Kopieren beim Schreiben sich darum kümmert :)

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

Beispiel Vererbungsstruktur mit ein wenig schmutziger und direkter Verwendung am Ende in der Funktion namens "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 Beispiel()
{
    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 erhältst du Vererbung und sie werden per Referenz übergeben, Strukturen haben keine Vererbung und werden durch Wert übergeben.

Es gibt großartige WWDC-Sitzungen zu Swift, diese spezifische Frage wird in einer von ihnen ausführlich beantwortet. Stelle sicher, dass du sie anschaust, da sie dich viel schneller auf den neuesten Stand bringen als der Sprachführer oder das iBook.

0 Stimmen

Könnten Sie einige Links zu dem bereitstellen, was Sie erwähnt haben? Denn auf der WWDC gibt es eine Menge zur Auswahl, ich würde gerne denjenigen ansehen, der dieses spezielle Thema behandelt.

0 Stimmen

Für mich ist dies ein guter Start hier: github.com/raywenderlich/…

2 Stimmen

Er spricht wahrscheinlich über diese großartige Sitzung: Protokollorientierte Programmierung in Swift. (Links: Video, Transkript)

3voto

Balasubramanian Punkte 4786

In Swift wurde ein neues Programmiermuster eingeführt, das als protokollorientierte Programmierung bekannt ist.

Erstellungsmuster:

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

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


Flache Kopie dupliziert nur die Referenz, die auf diese Objekte zeigt, während Tiefe Kopie die Referenz des Objekts dupliziert.


Die Implementierung einer Tiefenkopie für jeden Referenztyp ist zu einer mühsamen Aufgabe geworden. Wenn Klassen weitere Referenztypen enthalten, müssen wir das Prototypenmuster für jedes der Referenzeigenschaften implementieren. Und dann müssen wir tatsächlich den gesamten Objektgraphen kopieren, indem wir das NSCopying-Protokoll implementieren.

class Kontakt{
  var vorname:String
  var nachname:String
  var arbeitsAdresse:Adresse // Referenztyp
}

class Adresse{
   var straße:String
   ...
} 

Durch 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 zur Verwendung von Klassen zwingt. 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 Klassenreferenztyp 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 und dennoch Änderungen an den Eigenschaften des Objekts zulässt, während man dies mit einer Struktur nicht tun kann.

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 mit var auf einen anderen Wert zurücksetzen, um dies zu ermöglichen, da ein konstanter Werttyp in Swift ordnungsgemäß null Mutation zulässt, während Referenztypen (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