2016-09-12 8 views
23

Wie vermeide ich die Verwendung der! Eine Operation, die eine Kraftentpackung ausführt, ist normalerweise eine schlechte Option.Wie vermeidet man das Auspacken einer Variablen?

Was ist die bessere Option mit Code wie der folgenden, wo die Verwendung macht es den Code einfacher aussehen und wegen der Überprüfung der Variablen! Angerufen wird nie Null und so kann nicht abstürzen.

Mein Kursleiter stellte uns dem (!) Operator vor und forderte uns auf, ihn nie wieder zu benutzen. Uns sagen, warum natürlich, dass es unsere App zum Absturz bringen wird, wenn das optionale NULL ist.

Allerdings finde ich mich in Situationen wie diesen, in denen der Knall-Operator die prägnanteste und sicherste Option zu sein scheint.

func fullName() -> String { 
    if middleName == nil { 
     return "\(firstName) \(lastName)" 
    }else{ 
     return "\(firstName) \(middleName!) \(lastName)" 
    } 
} 

Gibt es eine bessere Möglichkeit, so etwas zu tun?

Auch hier ist die ganze Klasse, wenn sich jemand fragt.

class CPerson{ 
    var firstName: String 
    var middleName: String? 
    var lastName: String 

    init(firstName: String, middleName: String?, lastName: String) { 
     self.firstName = firstName 
     self.middleName = middleName 
     self.lastName = lastName 
    } 
    convenience init(firstName: String, lastName: String) { 
     self.init(firstName: firstName, middleName: nil, lastName: lastName) 
    } 
    func fullName() -> String { 
     if middleName == nil { 
      return "\(firstName) \(lastName)" 
     }else{ 
      return "\(firstName) \(middleName!) \(lastName)" 
     } 
    } 
} 

Mein Lehrer sagte O_O

+0

Bitte bearbeiten Sie, um beide Versionen des Codes - mit und ohne "bang" –

Antwort

23

die if let oder guard Konstrukte verwenden:

func fullName() -> String { 
    if let middleName = middleName { 
     return "\(firstName) \(middleName) \(lastName)" 

    } else { 
     return "\(firstName) \(lastName)" 
    } 
} 

func fullName() -> String { 
    guard let middleName = middleName else { 
     return "\(firstName) \(lastName)" 
    } 
    return "\(firstName) \(middleName) \(lastName)" 
} 

ich die guard Aussage in der Vollständigkeit halber gesetzt haben, aber wie andere bemerkt haben, dies wird häufig auch in einem Fehler verwendet/Fehlerfall.

Ich würde auch davon abraten, String-Interpolation für Strings zu verwenden. Sie sind bereits Zeichenfolgen, es ist nicht erforderlich, die description jedes Namens in einer neuen Zeichenfolge zu verwenden.

Betrachten return firstName + " " + lastName. Siehe Difference between String interpolation and String initializer in Swift für Fälle, in denen die String-Interpolation zu einem unerwarteten Ergebnis führen kann.

+7

Seien Sie sehr vorsichtig mit der Syntax "string +" "+ string". Dies kann dazu führen, dass Kompilierungszeiten explodieren. Gekettete '+' Operatoren führen sehr oft zu O (n!) Zeit, um die richtigen Typen herauszufinden. Es ist wahrscheinlich die häufigste Ursache für massive Kompilierungszeiten, die ich in der Wildnis sehe. Interpolation kompiliert viel, viel schneller. –

+0

Für mich bedeutet 'guard' einen Fehler- oder Fehlerfall. Und Sie könnten mehrere davon separat haben. I.e. Schutz someRequiredValue! = Nil else { Rückgabe "error" } Schutz anderenfalls!= nil else { return "Fehler" } zurück "normaler Rückgabewert" –

+1

@MattHorst Haben Sie mein Update über 'guard' gesehen? Ich habe es eingefügt, um zu zeigen, wie es mit dem Haftungsausschluss funktioniert, dass es häufiger in einem Fehlerfall verwendet wird. – JAL

5

Was hast du arbeiten und in der Tat: „Wenn ich Sie sehe den Knall-Operator, wir kämpfen werden“, wenn Sie sich nicht null wissen, mit! ist ein korrekter Weg, um es auszupacken.

Swift verfügt jedoch über eine Funktion namens optionale Bindung (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html).

In Ihrem Fall würde es so sein:

func fullName() -> String { 
     if let middle = middleName { 
      return "\(firstName) \(middleName) \(lastName)" 
     } else { 
      return "\(firstName) \(lastName)" 
     } 
    } 

Was die optionale Bindung tut, ist, wie Apple in den obigen Link sagt: „Sie verwenden optionale Bindung, um herauszufinden, ob ein optionaler Wert enthält, und wenn ja, diesen Wert als temporäre Konstante oder Variable verfügbar zu machen. " Innerhalb Ihrer Klammern haben Sie Zugriff auf middle und können es als bekanntes Nicht-Nil verwenden.

Sie können diese auch verketten, sodass Sie Zugriff auf mehrere temporäre Konstanten haben und if-Anweisungen nicht verketten müssen. Und Sie können sogar eine where Klausel verwenden, um eine optionale Bedingung auszuwerten. Wieder von der Apple-docs oben:

if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber { 
    print("\(firstNumber) < \(secondNumber)") 
} 
+2

ich stimme mit den anderen Posts, die Sie brauchen nicht zu verwenden, eine Prüfung wie folgt, für diesen Fall von String-Verkettung. Allerdings denke ich, wie ich es oben habe ist besser als Wächter. Für mich würde Wächter einen Fehlerfall bedeuten. –

16

Ihr Lehrer ist im Großen und Ganzen richtig. Definitiv in diesem Fall. Es gibt keinen Grund, diesen speziellen Fall zu machen und doppelten Code zu erzwingen.

Dies verbindet nur alle Nicht-Nil-Teile des Namens mit Leerzeichen. Die anderen Antworten hier sind auch in Ordnung, aber sie skalieren nicht so gut, um weitere optionale Teile hinzuzufügen (wie ein "Mr." -Titel oder "Jr." -Suffix).

(Dies ist in swift3 Syntax. Swift 2 sehr ähnlich ist, ist es joinWithSeparator(_:) statt.)

+1

Vielen Dank Rob. Wenn ich zwei Antworten akzeptieren könnte, würde ich auch deine annehmen. –

+1

Offensichtlich beschränkt dies die Art der Formatierung, die Sie haben. Wenn Sie "Smith, John James" oder "Smith, John" ausgeben möchten, funktioniert das nicht. Und wenn eine kleine Änderung in der Spezifikation eine große Änderung des Codes erfordert, ist Ihr Code möglicherweise nicht richtig. Mit dem ursprünglichen Code wäre diese Änderung trivial. – gnasher729

+0

@ gnasher729 Wahr.Es ist schwierig, diesen Code so zu schreiben, dass er gegen viele verschiedene Änderungen, die auftreten können, robust ist. Ein Weg begünstigt das Hinzufügen von zufälligen neuen Feldern (insbesondere optionalen), schlägt jedoch fehl, wenn das Format inkonsistent wird. Der andere bevorzugt Änderungen im Format auf zufällige Weise, aber wird sehr komplex, um viele optionale Felder zu behandeln. Ein gutes Beispiel dafür, wie etwas leicht zu erweitern ist, ist oft viel schwieriger als es klingt; Es gibt keine einzige Antwort, die alle Grundlagen abdeckt. –

2

Bevor eine optionale Variable Abwickeln sollten Sie müssen für nil überprüfen sonst Ihre Anwendung abstürzt, wenn die Variable nil enthalten.

  1. if let
  2. guard
  3. if-else
  4. mit ternären Operator
  5. Nil koaleszierende Betreiber

Und die man verwenden vollständig: und Schecks können auf verschiedene Weise, wie durchgeführt werden hängt von der Anforderung ab.

Sie können nur diesen Code ersetzen

if middleName == nil { 
    return "\(firstName) \(lastName)" 
}else{ 
    return "\(firstName) \(middleName!) \(lastName)" 
} 

von

return "\(firstName)\(middleName != nil ? " \(middleName!) " : " ")\(lastName)" 

ODER

Sie auch Nil coalescing operator (a ?? b) auspackt optional ein verwenden können, wenn es enthält ein Wert oder gibt einen Standardwert b zurück, wenn a null ist.

0

In diesem Fall liegt Ihr Lehrer falsch. Deine Funktion ist absolut sicher. middleName ändert sich nicht von nil zu nil hinter deinem Rücken. Ihre Funktion kann abstürzen, wenn Sie einen Tippfehler machen, und den Namen einer anderen Variablen anstelle von middleName eingeben, aber das wäre sowieso ein Fehler und der Absturz würde Sie zum Bug führen.

Aber normalerweise "wenn lassen ..." ist der bessere Weg, damit umzugehen, weil es den Test und das Auspacken kombiniert.

Es gibt auch Situationen, in denen Sie nicht sagen "wenn es Null ist, wird es abstürzen, das ist schlecht", aber "wenn es Null ist, dann will ich es abstürzen" (normalerweise weil Sie wissen, dass es nur Null sein kann, wenn es da ist ist ein Fehler irgendwo in Ihrem Code). In diesem Fall ! macht genau das, was du willst.

+4

Wenn es einen "besseren Weg" gibt, dann scheint es, dass sein Lehrer nicht falsch ist. – Insane