【问题标题】:Swift number generics?Swift 数字泛型?
【发布时间】:2015-02-11 14:48:26
【问题描述】:

我有这个函数可以根据 2 个数字计算斜边

func hypotenusa<T>(nr1: T, nr2: T) -> T {
    return sqrt( pow(nr1, 2) + pow(nr2, 2) )
}

// v Simpler situation v

func addition<T>(nr1: T, nr2: T) -> T {
    return nr1 + nr2
}

我想使用泛型,所以我不必制作 3 个分别使用 Int、Float、Double 的副本

但这不起作用,我认为泛型真的很难使用,请帮助我:)

【问题讨论】:

    标签: ios swift generics


    【解决方案1】:

    使用 Swift 5,根据您的需要,您可以选择以下方法之一来解决您的问题。


    #1。使用FloatingPoint协议作为参数泛型约束

    Apple Developer Documentation for FloatingPoint 显示以下hypotenuse 函数实现作为FloatingPoint 用法的示例:

    func hypotenuse<T: FloatingPoint>(_ a: T, _ b: T) -> T {
        return (a * a + b * b).squareRoot()
    }
    
    let (dx, dy) = (3.0, 4.0)
    let result = hypotenuse(dx, dy)
    print(result) // prints: 5.0
    

    #2。使用AdditiveArithmetic协议作为参数泛型约束

    AdditiveArithmetic 有以下声明:

    具有支持加法和减法的值的类型。

    下面的 Playground 示例代码显示了 AdditiveArithmetic 作为函数参数通用约束的可能用法:

    func addition<T: AdditiveArithmetic>(a: T, b: T) -> T {
        return a + b
    }
    
    let result = addition(a: 3, b: 4)
    print(result) // prints: 7
    

    #3。使用Numeric协议作为参数泛型约束

    Numeric 具有以下声明:

    具有支持乘法的值的类型。

    下面的 Playground 示例代码显示了 Numeric 作为函数参数通用约束的可能用法:

    func multiply<T: Numeric>(a: T, b: T, c: T) -> T {
        return a * b * c
    }
    
    let result = multiply(a: 3, b: 4, c: 5)
    print(result) // prints: 60
    

    请注意,Numeric 协议继承自 AdditiveArithmetic 协议。


    Apple 开发者文档包含所有数字协议的专用页面:Numeric Protocols

    【讨论】:

    • 请注意,已经可用的hypot 函数已经可以与CGFloat 一起使用一段时间了。
    【解决方案2】:

    Swift 泛型不像 C++ 模板。

    在 C++ 中,您可以根据需要尝试使用参数化类型,并且在编译器尝试使用不支持您的模板尝试执行的操作的某种类型实例化模板之前,这不是错误。

    在 Swift 中,泛型构造只能以在首次解析泛型构造时已知有效的方式使用参数化类型。您可以通过使用协议约束参数化类型来指定这些“已知有效的方式”。

    您不能使用泛型类型的参数调用sqrtpow,因为这些函数本身不是泛型的。它们各有两个定义:

    func pow(_: Double, _: Double) -> Double
    func pow(lhs: Float, rhs: Float) -> Float
    func sqrt(x: Double) -> Double
    func sqrt(x: Float) -> Float
    

    您可以编写hypotenusa 的特定类型版本:

    func hypotenusa(a: Float, b: Float) -> Float
    func hypotenusa(a: Double, b: Double) -> Double
    func hypotenusa(a: CGFloat, b: CGFloat) -> CGFloat
    

    我不知道你为什么要创建一个Int 版本,因为很少有直角三角形有整数斜边。

    无论如何,您根本不需要定义FloatDouble 版本,因为标准库已经提供了在FloatDouble 上定义的hypot 函数:

    func hypot(_: Double, _: Double) -> Double
    func hypot(lhs: Float, rhs: Float) -> Float
    

    您可以为CGFloat 创建另一个覆盖:

    func hypot(l: CGFloat, r: CGFloat) -> CGFloat {
        return hypot(Double(l), Double(r))
    }
    

    至于您的addition 函数,它与您的hypotenusa 函数存在相同的问题:+ 运算符没有完全通用定义。它有一些通用定义(与sqrtpow 不同),但这些定义仅涵盖整数类型(参见IntegerArithmeticType)。 + 没有涵盖浮点类型的通用定义。 Swift 使用显式类型定义了所有这些版本的 +

    func +(lhs: Float, rhs: Float) -> Float
    func +<T>(lhs: Int, rhs: UnsafePointer<T>) -> UnsafePointer<T>
    func +<T>(lhs: UnsafePointer<T>, rhs: Int) -> UnsafePointer<T>
    func +(lhs: Int, rhs: Int) -> Int
    func +(lhs: UInt, rhs: UInt) -> UInt
    func +(lhs: Int64, rhs: Int64) -> Int64
    func +(lhs: UInt64, rhs: UInt64) -> UInt64
    func +<T>(lhs: Int, rhs: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
    func +<T>(lhs: UnsafeMutablePointer<T>, rhs: Int) -> UnsafeMutablePointer<T>
    func +(lhs: Int32, rhs: Int32) -> Int32
    func +(lhs: UInt32, rhs: UInt32) -> UInt32
    func +(lhs: Int16, rhs: Int16) -> Int16
    func +(lhs: UInt16, rhs: UInt16) -> UInt16
    func +(lhs: Int8, rhs: Int8) -> Int8
    func +(lhs: UInt8, rhs: UInt8) -> UInt8
    func +(lhs: Double, rhs: Double) -> Double
    func +(lhs: String, rhs: String) -> String
    func +(lhs: Float80, rhs: Float80) -> Float80
    

    【讨论】:

    • 我明白了。我不知道hypot()哈哈我觉得很傻=S所以也许泛型没有我想象的那么先进:(
    • Float80 没有为 sqrt 或 pow 定义,您需要自己编写或使用类似 boost 的库
    【解决方案3】:

    我认为this 是你所需要的:

    您需要显式创建一个新协议并扩展您想要的类型(Int、Float、Double)以符合该协议。比在您的通用声明中所做的 func addition&lt;T: protocolJustCreated&gt;(nr1: T, nr2: T) -&gt; T {}

    阅读我链接的答案以获得更完整的答案。此处无需赘述。

    【讨论】:

      【解决方案4】:

      Sqrt() 和 pow() 都将它们的参数指定为 double 或 float。为了实现将这一函数用于 Int、Float 和 Double 的目标,您还需要创建 sqrt() 和 pow() 函数的泛型。

      【讨论】:

      • 如果您重新加载问题,我添加了一个更简单的情况。在返回行的那个 add() 中,我收到一个错误“无法调用 + 参数为 typ (T, T)”
      猜你喜欢
      • 2023-03-19
      • 1970-01-01
      • 2018-05-21
      • 2017-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多