2017-02-15 3 views
2

Wenn ich Folgendes tun:Binärer Operator '*' kann nicht auf Operanden vom Typ 'Float' und 'Float!' Angewendet werden.

let gapDuration = Float(self.MONTHS) * Float(self.duration) * self.gapMonthly; 

ich den Fehler:

Binary operator '*' cannot be applied to operands of type 'Float' and 'Float!' 

Aber wenn ich tun:

let gapDuration = 12 * Float(self.duration) * self.gapMonthly; 

Alles funktioniert gut. Ich habe keine Ahnung, was dieser Fehler mir sagt.

self.gapMonthly ist vom Typ Float! und self.duration und self.MONTHS sind vom Typ Int!

+2

Erwägen Sie, nicht optionale Typen so weit wie möglich zu verwenden. Könnten beispielsweise "Monate" in der Praxis nie "Null" sein? – vadian

Antwort

5

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 anil 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 anil ist, wird d initialisiert auf nil.

+0

Fühlen Sie sich frei, [melden Sie einen Fehlerbericht] (https://bugs.swift.org) darüber. – Hamish

Verwandte Themen