2017-05-20 2 views
2

Ich fand nur eine andere Möglichkeit, Protokolle und Protokollerweiterungen in Swift verwenden, indem Sie das optionale Protokoll erweitern, um eine Funktion hinzuzufügen, so dass ich Standardwerte bereitstellen kann.Swift, wo Bedingung zu prüfen, ob eine Eigenschaft implementiert ist

Ich schrieb eine Blog-Post über diese hier: https://janthielemann.de/random-stuff/providing-default-values-optional-string-empty-optional-string-swift-3-1/

Der Kern der Post ist, dass ich eine saubere und einfache Art und Weise benötigen Standardwerte für optionalen String, die null oder leer sind zu liefern. Um dies zu tun, habe ich ein Emptyable Protokoll Ende das Fakultativprotokoll wie so erweitert:

protocol Emptyable { 
    var isEmpty: Bool { get } 
} 

extension Optional where Wrapped: Emptyable { 
    func orWhenNilOrEmpty<T: Emptyable>(_ defaultValue: T) -> T { 
     switch(self) { 
     case .none: 
      return defaultValue 
     case .some(let value) where value.isEmpty: 
      return defaultValue 
     case .some(let value): 
      return value as! T 
     } 
    } 
} 

extension String: Emptyable {} 

Nun ist die Frage: Gibt es eine Möglichkeit kann ich des Emptyable Protokoll loszuwerden und haben stattdessen eine bedingte Prüfung, ob oder nicht eine Eigenschaft oder Funktion ist durch den generischen Typ implementiert, so dass ich oderWhenNilOrEmpty() für jeden Typ automatisch erhalten, der isEmpty hat?

UPDATE

Wie Paulo vorgeschlagen, wird der T-generic eigentlich nicht braucht, und ich erstellt so einen Operator für noch schnelleren Zugriff und bequeme Nutzung (zumindest glaube ich. Fühlen Sie sich frei, mich zu korrigieren, mich bin immer glücklich, neue Dinge zu lernen und mich zu verbessern.

Ich nenne es die "nicht leere Nil Coalescing" -Operator (wer kann mit einem besseren Namen kommen? Ich fühle mich wie ich saugen Dinge benennen: /). Hoffentlich ein Tag, es hilft jemand:

protocol Emptyable { 
    var isEmpty: Bool { get } 
} 

infix operator ???: NilCoalescingPrecedence 

extension Optional where Wrapped: Emptyable { 
    func orWhenNilOrEmpty(_ defaultValue: Wrapped) -> Wrapped { 
     switch(self) { 
     case .none: 
      return defaultValue 
     case .some(let value) where value.isEmpty: 
      return defaultValue 
     case .some(let value): 
      return value 
     } 
    } 

    static func ???(left: Wrapped?, right: Wrapped) -> Wrapped { 
     return left.orWhenNilOrEmpty(right) 
    } 
} 

extension String: Emptyable {} 

extension Array: Emptyable {} 

extension MyStruct: Emptyable { 
    let text: String 
    let number: Int 
    var isEmpty: Bool { return text.isEmpty && number == 0 } 
    init(text: String, number: Int) { 
     self.text = text 
     self.number = number 
    } 
} 

let mandatoryNotEmptyString = optionalOrEmptyString ??? "Default Value" 
let mandatoryNotEmptyStruct = optionalOrEmptyStruct ??? MyStruct(name: "Hello World", number: 1) 
+0

Muss Ihre 'orWhenNilOrEmpty'-Funktion wirklich generisch sein? Kannst du 'T' nicht durch' Wrapped' ersetzen? Oder ist Ihre API so entworfen, dass sie willkürlich typisierte Standardwerte unterstützt (aber Ihre erzwungene Umwandlung in der letzten Zeile kann immer erfolgreich sein, wenn dies der Fall ist)? –

+0

Sie haben Recht. T wird überhaupt nicht benötigt. Danke für den Tipp! – xxtesaxx

Antwort

1

Nein, Sie können nicht abgefragt werden, ob ein Objekt oder den Wert eine bestimmte Eigenschaft als Einschränkung auf einer derartigen Verlängerung ohne ein Protokoll. Dies würde eine Reflexion erfordern, wie sie derzeit in Swift nicht implementiert ist. Außerdem kann eine isEmpty-Eigenschaft für verschiedene Typen unterschiedliche Bedeutungen haben. Daher könnte das Testen auf das Vorhandensein einer Methode oder Eigenschaft anstelle eines Protokolls zu unerwartetem Verhalten führen.

könnten Sie schreiben gerade

if let unwrappedString = optionalString, !unwrappedString.isEmpty { 
    // Do stuff 
} else { 
    // Use default value 
} 

kein Protokoll oder erforderliche Erweiterung und sehr gut lesbar.

In Swift 4, die in diesem Herbst herauskommt, String will conform to BidirectionalCollection, die von Collection erbt. Das Collection Protokoll bietet eine isEmpty Eigenschaft, so dass Ihre Erweiterung

extension Optional where Wrapped: Collection { 
    // ... 
} 

sein könnte Aber selbst dann sollten Sie leere Zeichenfolge auf Null setzen, wenn sich in erster Linie zu speichern, weil Sie haben jetzt zwei Zustände (nil und leer) die genau das gleiche zu repräsentieren scheinen.

+0

Spiegel kann nicht als Einschränkung für eine Erweiterung verwendet werden. Und die Methode für jeden optionalen Wert unabhängig vom umhüllten Typ bereitzustellen, wäre wirklich schlecht. – Palle

+0

Natürlich haben Sie Recht! Ich dachte über ein alternatives Design nach ... trotzdem, danke;) –

+2

Das "let x = y,! X.isEmpty ..." war genau das, was ich loswerden wollte.:) Wie auch immer, ich dachte schon, dass es nicht möglich ist, nach der Funktion oder der Anwesenheit von Objekten zu suchen, also danke für die Bestätigung. Übrigens ging ich jetzt noch einen Schritt weiter und machte meine Funktion zu einem Operator namens ???. Vielleicht ein bisschen übertrieben, aber es ist eher eine Lernmöglichkeit für mich, als es in realen Kundenprojekten zu verwenden. Nun, in meinen eigenen Projekten werde ich wahrscheinlich davon Gebrauch machen: D – xxtesaxx

Verwandte Themen