webentwicklung-frage-antwort-db.com.de

Warum haben Aufzählungen berechnete Eigenschaften, aber keine in Swift gespeicherten Eigenschaften?

Ich bin neu bei Swift und bin gerade in der Dokumentation darauf gestoßen:

Berechnete Eigenschaften werden von Klassen, Strukturen und .__ bereitgestellt. Aufzählungen. Gespeicherte Eigenschaften werden nur von Klassen und .__ bereitgestellt. Strukturen.

Warum das? Funktionieren zugehörige Enumerationswerte wie gespeicherte Eigenschaften? Es scheint, als hätten sie Eigenschaften anfangs gespeichert - Warum keine Eigenschaften für gespeicherte Typen für Klassen in swift?

22
Adit Gupta

enums haben type - Eigenschaften gespeichert, d. h. static-Eigenschaften. Sie haben keine instance -Eigenschaften gespeichert. Ich weiß nicht, ob es einen technischen Grund gibt, warum gespeicherte Instanzeigenschaften für enums nicht verfügbar sind. Sie müssen möglicherweise Ihre Frage im dev-Forum stellen, wenn Sie eine technische Antwort auf "warum" wünschen.

In Ihrer Frage fragen Sie, ob verknüpfte Werte wie gespeicherte Eigenschaften funktionieren. Tatsächlich sind sie (in gewisser Hinsicht) flexibler als gespeicherte Eigenschaften für structs und classes. Jede case in einer enum kann einen eigenen spezialisierten Datensatz haben, der ihr zugeordnet ist. Anstatt einen Satz von gespeicherten Eigenschaften zu haben, der für alle cases gilt, können Sie die gespeicherten Eigenschaften für jede case individualisieren.

12
Aaron Rasmussen

Enums, die keine gespeicherten Instanzeneigenschaften zulassen, ist eine Entwurfsauswahl. Enum mit gespeicherten Instanzeneigenschaften macht es wie eine Struktur (mit enum-Supermächten), aber gerade aus der Typperspektive verhält sich das Enum nun wie Typmultiplikatoren. Grundsätzlich betrachten

enum Set1 {
    case a
    case b
    case c
}

enum Times {
    case x
    case y

    var k: Set1
}

Was dies eigentlich bedeutet, dass das Enum Times uns erlaubt, eine beliebige Kombination von Elementen aus Set1 und Set2 zu haben, was zu 6 verschiedenen Fällen führt, aber warten Sie, wir wissen, dass dies ein Zweck eines Tupel-Typs ist, wie (Set1, Set2), für den Times deklariert werden kann 

typealias Times = (Set1, Set2)

Ich hoffe, dass dies eine vernünftige Begründung dafür ist, den früheren Fall nicht zuzulassen. 

Allerdings erlaubt es Swift Enums, jedem case ein beliebiges n-Tuple zuzuordnen, wodurch wir in der funktionalen Programmierung eine so genannte diskriminierte Vereinigung deklarieren können. Nennen Sie es eine gespeicherte Eigenschaft, die an case angehängt ist, wenn Sie möchten. Aus Typperspektiven fungiert er jetzt als Typaddierer. 

enum Add {
    case lhs(Set1)
    case rhs(Set2)
}

Wir haben jetzt 5 verschiedene Fälle. Wenn wir jetzt 2-Tupel speichern:

enum AddTimes {
    case lhs(Set1, Set2)
    case rhs(Set3, Set4)
}

wir haben jetzt im Grunde die Summe der Multiplikationen (Set1 * Set2 + Set3 * Set4) . Dies ist ein sehr leistungsfähiges Werkzeug, wenn es um die Mustererkennung geht.

JEDOCH, gibt es einige Fälle, in denen Sie die Form der gespeicherten Eigenschaft in enum emulieren möchten. Bedenken Sie:

public enum Service {
    case registerNewUser(username: String, password: String, language: String)
    case login(username: String, password: String, deviceTokenº: String?)
    case logout(sessionToken: String)
    case sendForgotPassword(email: String)
}

ist eine deklarative Methode zum Definieren von REST -Endpunkten (in Frameworks wie Moya ) Wenn Sie eine Anfrage auslösen möchten, würden Sie so etwas tun 

MoyaProvider<Service>.request(.sendForgotPassword(email: "[email protected]"))

Stellen Sie sich nun vor, Sie möchten zwischen Ihrem Produktions- und Testserver unterscheiden. Wenn Sie jeweils einen Server als weiteres Tuple-Element hinzufügen:

case forgotPassword(sessionToken: String, serverBaseURLString: String)

dies hat eine falsche Semantik, da Sie ursprünglich beabsichtigen, dass jeder Tupel Anforderungsparameter speichert, jetzt jedoch eine Server-Basisadresse.

Um dies zu vermeiden, können wir unseren Typ auf folgende Weise tatsächlich parametrieren. Anstatt dass Server definiert wird als:

enum Server: String {
    case production = "https://service.info"
    case test = "http://test.service.info"
}

wir können es für jeden Fall mit unterschiedlichen Typen definieren:

public struct ProductionServer: ServerType {
    public static var baseURLString: String { return "https://service.info" }
}
public struct TestServer: ServerType {
    public static var baseURLString: String { return  "http://test.service.info" }
}
public protocol ServerType {
    static var baseURLString: String { get }
}

und schließlich parametrieren Sie unseren ServiceType als 

public enum Service<T> where T: ServerType {
    case registerNewUser(username: String, password: String, language: String)
    case login(username: String, password: String, deviceTokenº: String?)
    case logout(sessionToken: String)
    case sendForgotPassword(email: String)

    var serverURL: URL {
        return T.baseURL
    }
}

public typealias ProdutionService = Service<ProductionServer>
public typealias TestService = Service<TestServer>
13
ambientlight

Ich verwende einen kleinen Trick, um Eigenschaften zu speichern, die bei der Initialisierung nicht zugänglich sind. 

Zuerst erstelle ich eine Klasse Future, in der die gespeicherte Eigenschaft gespeichert wird: 

class Future<T> {
  var value: T?
  init(value: T? = nil) {
      self.value = value
  }
}

Dann erstelle ich mein Enum: 

enum Sample {
  case Test(future: Future<String>)
}

Instanziieren:

let enumTest = Sample.Test(future: Future())

Später im Code: 

switch enumTest {
  case let .Test(future):
  future.value = "Foo"
}

Und später können Sie auf den Wert zugreifen:

switch enumTest {
  case let .Test(future):
  // it will print Optional("Foo")
  print("\(future.value)")
}

Sie sollten dies nicht missbrauchen, aber in manchen Fällen kann es hilfreich sein. 

Ich hoffe es hilft.

4
manueGE

Ein Enum wird als strukturierter Datentyp betrachtet, der geändert werden kann, ohne dass mehrmals innerhalb eines Codes ein String oder ein Int. Geändert werden muss. Mit einem Enum können wir uns nie darum kümmern, dasselbe mehr als einmal zu ändern. Zum Beispiel Dropdown-Menü: 

enum DropDownMenuOptions: String {
  case MenuOptionOne
  case MenuOptionTwo
  case MenuOptionThree
}

Mit gespeicherten Eigenschaften können Sie benötigte Informationen vorberechnen und den Code in Ihrer Hauptfunktion reduzieren. Bestes Beispiel ist die Berechnung der Größe von rect:

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct Rect {
    var Origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = Origin.x + (size.width / 2)
            let centerY = Origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            Origin.x = newCenter.x - (size.width / 2)
            Origin.y = newCenter.y - (size.height / 2)
        }
    }
}

var square = Rect(Origin: Point(x: 0.0, y: 0.0),
    size: Size(width: 10.0, height: 10.0))
0