Schnelle Konstanten: Struct oder Enum

78

Ich bin mir nicht sicher, welche von beiden Konstanten besser definieren können. Eine Struktur oder eine Aufzählung. Eine Struktur wird jedes Mal kopiert, wenn ich sie benutze oder nicht? Wenn ich an eine Struktur mit static letKonstanten denke , macht es meiner Meinung nach keinen Sinn, dass sie ständig kopiert wird. Aber wenn es nicht kopiert wird, spielt es keine Rolle, was ich nehme?

Welche Vorteile bringt die Wahl einer Struktur oder Aufzählung?

Francisco sagt, benutze Struct's.

Ray Wenderlich sagt, benutze Enums. Aber mir fehlt die Rechtfertigung.

Paixsn
quelle
3
Eine Begründung finden Sie im verlinkten Artikel: "Der Vorteil der Verwendung einer Aufzählung ohne Groß- und Kleinschreibung besteht darin, dass sie nicht versehentlich instanziiert werden kann und als reiner Namespace fungiert."
Martin R
OK, das klingt logisch. Daher sollte ich in 90% meiner Fälle Aufzählungen verwenden. Und sobald etwas instanziiert oder variabel sein muss, verwende ich eine Struktur. Richtig?
Paixsn
2
Warum definieren Sie sie nicht in Klassen, die sie verwenden? Warum müssen Sie alle Konstanten in einer Struktur platzieren? Sie können sie weiterhin in einer Datei haben, wenn Sie Erweiterungen verwenden. Wenn Sie sich zwischen enum und struct entscheiden, sage ich aus architektonischer Sicht beides nicht.
Sulthan
Weil ich ein Framework brauche, das ich in einen großen Teil meiner Projekte einbeziehen kann. Ich werde in allen die gleichen Konstanten brauchen. Ich möchte es also nicht mehrmals schreiben.
Paixsn
1
@SnowN Ich bin nicht gegen Konstanten, aber ich sage Ihnen, dass es nicht notwendig ist, sie alle in eine gemeinsame Struktur / Aufzählung zu setzen, wenn sie nichts gemeinsam haben.
Sulthan

Antworten:

127

Sowohl Strukturen als auch Aufzählungen funktionieren. Als Beispiel beides

struct PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

und

enum PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

arbeiten und definieren Sie eine statische Eigenschaft PhysicalConstants.speedOfLight.

Betreff: Eine Struktur wird jedes Mal kopiert, wenn ich sie benutze oder nicht?

Beide structund enumsind Werttypen, die auch für Aufzählungen gelten. Aber das ist irrelevant , weil man hier keinen Wert an alle erstellen muß: Statische Eigenschaften (auch als Typ selbst Objekte) sind Eigenschaften des Typs, nicht von einer Instanz dieses Typs.

Betreff: Welche Vorteile hat die Wahl einer Struktur oder Aufzählung?

Wie im verlinkten Artikel erwähnt :

Der Vorteil der Verwendung einer Aufzählung ohne Groß- und Kleinschreibung besteht darin, dass sie nicht versehentlich instanziiert werden kann und als reiner Namespace fungiert.

Also für eine Struktur,

let foo = PhysicalConstants()

Erstellt einen (nutzlosen) Wert vom Typ PhysicalConstants, aber für eine Aufzählung ohne Groß- und Kleinschreibung kann er nicht kompiliert werden:

let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers
Martin R.
quelle
Es gibt einen besonderen Fall mit switch-Anweisungen, in denen Sie keine Aufzählungen ohne Gehäuse verwenden können. Siehe meine Antwort zur Diskussion und mögliche Problemumgehungen.
Tim Fuqua
6
Kleinere Ergänzung: Wenn wir private init() {}das StructBeispiel ergänzen , hat es auch den "Vorteil", dass es nicht versehentlich im laufenden Betrieb instanziiert werden kann. (Natürlich könnte dieser "Vorteil" von einigen Entwicklern umgangen werden, indem ein Initialisierer in eine Erweiterung des Struct: aufgenommen wird. Wenn wir jedoch aus irgendeinem Grund lieber Structeinen "reinen Namespace" als einen verwenden möchten enum, dann den Ein privater Initialisierer könnte ein guter Schutz sein, um ihn nicht als Instanz zu verwenden.
dfrib
... und ich habe gerade festgestellt, dass genau dieser Punkt in der anderen Antwort unten (irgendwie) erwähnt wurde (obwohl das dort erwähnte private Problem mit derselben Datei in Swift 3 nicht mehr vorhanden ist).
dfrib
Das ist ein sehr unbrauchbarer Vorteil. Ich bin tatsächlich hierher gekommen, um einen Vergleich zwischen struct Constants static let speedOfLight = 300vs zu enum Constants enum Light : Int case speed = 300vergleichen. Können Sie diese auch in Ihrer Antwort vergleichen? Oder gibt es eine andere Antwort auf diesen Vergleich?
Honig
@Honey: Das ist eine andere Frage. In diesem (wie ich es verstanden habe) geht es darum, einen Namespace bereitzustellen. Statische Konstanten können innerhalb einer Struktur oder innerhalb einer Aufzählung definiert werden. Sie können unterschiedliche Typen haben, und Sie können mehrere Konstanten mit demselben Wert haben. - Die Fälle einer Aufzählung definieren (voneinander unterschiedliche) Werte desselben Typs.
Martin R
16

Hier eine kurze Antwort: Müssen Ihre Konstanten eindeutig sein? Verwenden Sie dann eine Aufzählung, die dies erzwingt.

Möchten Sie mehrere verschiedene Konstanten verwenden, um denselben Wert zu enthalten (häufig aus Gründen der Übersichtlichkeit hilfreich)? Verwenden Sie dann eine Struktur, die dies ermöglicht.

jglasse
quelle
1
Ich denke, er würde keine Einzelfälle verwenden, da er seitdem immer schreiben müssteStaticVars.pi.rawValue
Michael
7

Ein Unterschied zwischen den beiden besteht darin, dass Strukturen instanziiert werden können, wo dies bei Aufzählungen nicht möglich ist. In den meisten Szenarien, in denen Sie nur Konstanten verwenden müssen, ist es wahrscheinlich am besten, Aufzählungen zu verwenden, um Verwirrung zu vermeiden.

Zum Beispiel:

struct Constants {
    static let someValue = "someValue"
}

let _ = Constants()

Der obige Code wäre weiterhin gültig.

Wenn wir eine Aufzählung verwenden:

enum Constants {
    static let someValue = "someValue"
}

let _ = Constants() // error

Der obige Code ist ungültig und vermeidet daher Verwirrung.

SilentK
quelle
6

Verwenden von Xcode 7.3.1 und Swift 2.2

Obwohl ich Martin R zustimme und der Ray Wenderlich-Styleguide deutlich macht, dass Aufzählungen in fast allen Anwendungsfällen besser sind, da es sich um einen reinen Namespace handelt, gibt es einen Ort, an dem structTrümpfe verwendet werden enums.

Anweisungen wechseln

Beginnen wir mit der Strukturversion:

struct StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

Mit einer Struktur wird diese übereinstimmen und ausgedruckt Matched StaticVars.someString.

Betrachten wir nun die Hüllkurven-Enum-Version (indem Sie nur das Schlüsselwort structin ändern enum):

enum StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

Sie werden feststellen, dass in der switch-Anweisung in der case StaticVars.someString:Zeile ein Fehler bei der Kompilierung angezeigt wird. Der Fehler ist Enum case 'someString' not found in type 'String'.

Es gibt eine Pseudo-Problemumgehung, indem die statische Eigenschaft in einen Abschluss konvertiert wird, der stattdessen den Typ zurückgibt.

Sie würden es also folgendermaßen ändern:

enum StaticVars {
    static let someString = { return "someString" }
}

switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

Beachten Sie die Notwendigkeit von Klammern in der case-Anweisung, da es sich jetzt um eine Funktion handelt.

Der Nachteil ist, dass es jetzt, da wir es zu einer Funktion gemacht haben, jedes Mal ausgeführt wird, wenn es aufgerufen wird. Wenn es also nur ein einfacher primitiver Typ wie Stringoder ist Int, ist das nicht so schlimm. Es ist im Wesentlichen eine berechnete Eigenschaft. Wenn es sich um eine Konstante handelt, die berechnet werden muss und Sie sie nur einmal berechnen möchten, sollten Sie sie in eine andere Eigenschaft berechnen und den bereits berechneten Wert im Abschluss zurückgeben.

Sie können den Standardinitialisierer auch mit einem privaten überschreiben, und dann erhalten Sie die gleiche Art von Fehler beim Kompilieren von Fehlern wie bei der Aufzählung ohne Gehäuse.

struct StaticVars {
    static let someString = "someString"
    private init() {}
}

Damit möchten Sie jedoch die Deklaration der Struktur in eine eigene Datei einfügen. Wenn Sie sie in derselben Datei wie beispielsweise einer View Controller-Klasse deklarieren, kann die Datei dieser Klasse dennoch versehentlich eine nutzlose Datei instanziieren Instanz von StaticVars, aber außerhalb der Datei der Klasse würde es wie beabsichtigt funktionieren. Aber es ist dein Anruf.

Tim Fuqua
quelle
3
Anscheinend wurde dieses Problem behoben. Die "caseless enum version" wird wie erwartet in Xcode 8 Beta 6 kompiliert und ausgeführt.
Martin R
1
Direkt am! Ich mag es wirklich, Aufzählungen ohne Gehäuse für den Vorteil "keine Instanziierung" zu verwenden. Und ich bin auch froh, dass ich meinen Beitrag mit den Xcode-Versionsinformationen begonnen habe, sonst hätte es das Problem "funktioniert auf meinem Computer" geben können.
Tim Fuqua
@MartinR Wie Sie darauf hingewiesen haben, dass in Xcode 8 der Fall der "unbegründeten Aufzählung" sortiert ist, was ist nun der Unterschied zwischen der Deklaration der statischen Angabe in "struct" und der in "enum".
G.Abhisek
@ G.Abhisek: Ich habe versucht, das in meiner Antwort zu beantworten. Die Verwendung einer Aufzählung ohne Gehäuse verhindert, dass Sie eine (nutzlose) Instanz dieses Typs erstellen. Für die Konstante selbst macht es überhaupt keinen Unterschied.
Martin R
@MartinR Das bedeutet, dass wir beim Zugriff über eine Struktur unnötigerweise eine Instanz erstellen, während sie im Fall von enum als Namespace fungiert.
G.Abhisek
1

Im Combine- Framework hat Apple Enums für Namespaces bevorzugt.

enum Publishers

Ein Namespace für Typen, die als Herausgeber dienen.

enum Subscribers

Ein Namespace für Typen, die als Abonnenten dienen.

enum Subscriptions

Ein Namespace für Symbole, die sich auf Abonnements beziehen.

Ryan
quelle