ich dabei um einen Fehler (zumindest wird der Fehler irreführend) in Betracht ziehen würde, und scheint vorhanden zu sein, wenn ein binären zu verwenden versuchen, Operator für 3 oder mehr Ausdrücke, die zu einem bestimmten Typ ausgewertet werden, wobei einer oder mehrere dieser Ausdrücke implizit als Option dieses Typs nicht ausgepackt sind.
Dies dehnt den Typ-Checker einfach zu weit aus, da er alle Möglichkeiten der Behandlung der IUO als stark optional in Betracht ziehen muss (da der Compiler aufgrund SE-0054 eine IUO als stark optional behandelt, wenn sie typisiert werden kann) als einer überprüft), zusammen mit dem Versuch, die richtigen Überladungen für die Operatoren zu finden.
Auf den ersten Blick scheint es ähnlich zu dem in How can I concatenate multiple optional strings in swift 3.0? gezeigten Problem zu sein - aber dieser Fehler wurde in Swift 3.1 behoben, aber dieser Fehler ist immer noch vorhanden.
Ein minimales Beispiel, das das gleiche Problem wäre reproduziert:
let a: Float! = 0
// error: Binary operator '*' cannot be applied to operands of type 'Float' and 'Float!'
let b = a * a * a
und vorhanden ist, für andere Binäroperatoren andere als *
: in Float
Ausdrücke noch reproduzierbar beim Mischen
// error: Binary operator '+' cannot be applied to operands of type 'Float' and 'Float!'
let b = a + a + a
Es ist auch (solange mindestens ein Float!
Ausdruck vorhanden ist), sowie bei expliziter Annotation von b
als Float
:
let b: Float = a * a * a // doesn't compile
let a: Float! = 0
let b: Int = 0
let c: Int = 0
let d: Float = a * Float(b) * Float(c) // doesn't compile
Eine einfache Lösung für dieses wäre ausdrücklich zu zwingen, die implizit ungeöffneten optional (e) in den Ausdruck auszupacken:
let d = a! * Float(b) * Float(c) // compiles
Das entlastet der Druck auf den Typ-Checker, wie jetzt alle Ausdrücke zu Float
auswerten , so ist die Überladungsauflösung viel einfacher.
Obwohl es natürlich selbstverständlich ist, stürzt es ab, wenn a
nil
ist. Im Allgemeinen sollten Sie vermeiden, implizit unverpackte Optionale zu verwenden, und stattdessen lieber starke Optionals verwenden - und, wie @vadian says, verwenden Sie immer non-optionals in Fällen, in denen der Wert nil
keinen Sinn ergibt.
Wenn Sie ein optionales verwenden müssen und nicht 100% sicher sind, dass es einen Wert enthält, sollten Sie es vor der Arithmetik sicher auspacken. Eine Möglichkeit, dies zu tun wäre, Optional
‚s map(_:)
Methode zu verwenden, um die Optionalität zu propagieren:
let a: Float! = 0
let b: Int = 0
let c: Int = 0
// the (a as Float?) cast is necessary if 'a' is an IUO,
// but not necessary for a strong optional.
let d = (a as Float?).map { $0 * Float(b) * Float(c) }
Wenn a
ist ungleich Null, wird d
auf das Ergebnis des ungeöffneten Wertes von a
initialisiert werden, multipliziert mit Float(b)
und Float(c)
. Wenn jedoch a
nil
ist, wird d
initialisiert auf nil
.
Erwägen Sie, nicht optionale Typen so weit wie möglich zu verwenden. Könnten beispielsweise "Monate" in der Praxis nie "Null" sein? – vadian