在Swift 3.0

时间:2017-01-25 16:26:51

标签: swift floating-point swift3 swift-extensions

如何在Swift 3.0中紧凑地编写Array的扩展名,该扩展名适用于FloatDouble Element类型?

以下不起作用:

extension Array where Element: FloatingPoint
{
    public func multiply(mult: Double) -> [Double] {
        return self.map{Double($0) * mult}
    }
}

错误是

  

无法在当前上下文中推断闭包类型

为什么不能推断出闭包类型?这是编译器的当前限制,还是有充分理由不能推断出闭包类型?

更明确的版本也不起作用:

extension Array where Element: FloatingPoint
{
    public func multiply(mult: Double) -> [Double] {
        return self.map{(x: Element) -> Double in Double(v: x) * mult}
    }
}

这次出现错误

  

对成员'*'的歧义提及

我再也不确定这个错误的原因。

1 个答案:

答案 0 :(得分:2)

逻辑上,您的扩展应该通过将同类浮点类型数组与相同类型的值相乘并返回该类型的数组来工作。您可以使用Element类型的参数以及[Element]的返回来表达此信息:

// this could also just be an extension of Sequence
extension Array where Element : FloatingPoint {

    public func multiply(by factor: Element) -> [Element] {
        return self.map { $0 * factor }
    }
}

因此对于[Float],这会接受Float类型的参数并返回[Float]

  

但是,如果我确实想要返回Double数组?

,该怎么办?

我不相信可以从任意Double(或甚至FloatingPoint)符合的实例构建BinaryFloatingPoint协议(尽管它们确实需要实现IEEE 754规范的各个方面)实际上定义了符合类型的精确编码。

但是,如果真的想要这个,你可以写两个重载 - 一个用于Float元素,一个用于Double元素:

extension Sequence where Iterator.Element == Float {

    public func multiply(by factor: Double) -> [Double] {
        return self.map { Double($0) * factor }
    }
}

extension Sequence where Iterator.Element == Double {

    public func multiply(by factor: Double) -> [Double] {
        return self.map { $0 * factor }
    }
}

或者,如果您计划使用更广泛的类型进行此工作,则可以使用protocol来定义允许符合类型将其值表示为Double的要求:

protocol ConvertibleToDouble {
    func _asDouble() -> Double
}

extension Float : ConvertibleToDouble {
    func _asDouble() -> Double { return Double(self) }
}

extension Double : ConvertibleToDouble {
    func _asDouble() -> Double { return self }
}

extension Sequence where Iterator.Element : ConvertibleToDouble {

    func multiply(by factor: Double) -> [Double] {
        return self.map { $0._asDouble() * factor }
    }
}