为什么Float to Double的转换在运行时失败?

时间:2017-05-01 04:54:04

标签: swift casting floating-point type-conversion

我有以下代码:

func roughlyEq<T: FloatingPoint>(_ a: T, _ b: T) -> Bool {
  return abs(a - b) < (0.01 as! T)
}

当我使用Float类型的参数调用它时,我在运行时遇到崩溃:

Could not cast value of type 'Swift.Double' (0x10043e6a8) to 'Swift.Float' (0x10043e5e0)

这没有任何意义 - 0.01可以确实转换为Float,比如当我写Float(0.01)时。为什么会发生这种错误?

相反的方向也失败了:

Could not cast value of type 'Swift.Float' (0x1004ea5e0) to 'Swift.Double' (0x1004ea6a8).

如何让这种方法起作用?

2 个答案:

答案 0 :(得分:2)

因为DoubleFloat是完全不相关的类型。即Double不是类型/协议,是Float的超类型,反之亦然。

请注意,仅仅因为存在要在DoubleFloat之间来回转换的初始值设定项,并不意味着您可以在它们之间来回转换。

FloatingPoint协议可以很好地抽象浮点类型的行为,并完全根据Self定义大部分内容,并且永远不会假设Double或{ {1}}(或者任何具体类型)是一种比任何其他类型更特权或特殊的Float类型。

我认为没有办法使用泛型函数扩展Self,因为FloatingPointFloat操作本质上是非泛型的(因为它们受到限制)到具体类型,以及实现它们的硬件)。

以下是我将如何做到这一点:

Double

关键是protocol DoubleOrFloat: FloatingPoint, ExpressibleByFloatLiteral {} extension Float: DoubleOrFloat {} extension Double: DoubleOrFloat {} extension DoubleOrFloat { func roughlyEquals(_ other: Self) -> Bool { let closeEnoughThreshold: Self = 0.01 return abs(self - other) < closeEnoughThreshold } } 。这是可能的,因为let closeEnoughThreshold: Self = 0.01DoubleOrFloat的子类型,因此我们知道浮点文字ExpressibleByFloatLiteral可以转换为0.01(因为已知SelfSelf,暗示DoubleOrFloat)。

答案 1 :(得分:2)

亚历山大已经说过,你不能从Double强行施放 到Float。文字常量0.01的类型为Double 函数,如果as! TT

,广告Float将失败

一个简单的解决方案是为BinaryFloatingPoint定义函数 相反,它描述了一个&#34;二进制浮点类型&#34;并扩展了FloatingPoint协议。 所有常用的浮点类型(FloatDoubleCGFloat)符合BinaryFloatingPoint。 由于BinaryFloatingPoint也继承自 ExpressibleByFloatLiteral,您现在可以与之比较 0.01字面意思:

func roughlyEq<T: BinaryFloatingPoint>(_ a: T, _ b: T) -> Bool {
    return abs(a - b) < 0.01
}

此处0.01的类型从上下文推断为T

或作为协议扩展方法:

extension BinaryFloatingPoint {
    func roughlyEq(_ other: Self) -> Bool {
        return abs(self - other) < 0.01
    }
}