当我执行以下操作时:
let gapDuration = Float(self.MONTHS) * Float(self.duration) * self.gapMonthly;
我收到错误:
Binary operator '*' cannot be applied to operands of type 'Float' and 'Float!'
但是当我这样做时:
let gapDuration = 12 * Float(self.duration) * self.gapMonthly;
一切都很好。 我不知道这个错误告诉我的是什么。
self.gapMonthly
的类型为Float!
,self.duration
和self.MONTHS
的类型为Int!
答案 0 :(得分:5)
我认为这是一个错误(至少,错误是误导性的),并且当试图在3个或更多表达式上使用二元运算符时,它似乎存在,这些表达式计算为给定类型,其中一个或多个这些表达式是该类型的隐式解包的可选项。
这简单地延伸了类型检查器,因为它必须考虑将IUO视为强选项的所有可能性(因为SE-0054编译器会将IUO视为强选项,如果它可以被类型检查为一个),同时试图为运营商找到正确的重载。
乍一看,它似乎与How can I concatenate multiple optional strings in swift 3.0?中显示的问题相似 - 但是该错误已在Swift 3.1中修复,但此错误仍然存在。
重现相同问题的最小例子是:
let a: Float! = 0
// error: Binary operator '*' cannot be applied to operands of type 'Float' and 'Float!'
let b = a * a * a
并且存在于*
以外的其他二元运算符:
// error: Binary operator '+' cannot be applied to operands of type 'Float' and 'Float!'
let b = a + a + a
在Float
表达式中混合时(只要至少有一个Float!
表达式保留),以及明确地将b
注释为{{1}时,它仍然是可重现的}:
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
这减轻了类型检查器的压力,因为现在所有表达式都计算为let d = a! * Float(b) * Float(c) // compiles
,因此重载分辨率要简单得多。
虽然当然,如果Float
为a
,这将会崩溃。一般情况下,您应该尝试避免使用隐式展开的选项,而是更喜欢使用强选项 - 而且,如@vadian says一样,在值为nil
的情况下,始终使用非选项感。
如果你需要使用一个可选项并且不能100%确定它包含一个值,你应该在进行算术运算之前安全地打开它。一种方法是使用nil
的{{3}}方法来传播可选性:
Optional
如果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) }
为非零,则a
将初始化为展开后的值d
乘以a
和Float(b)
的结果。但如果Float(c)
为a
,则nil
将初始化为d
。