Swift数字泛型?

Arb*_*tur 5 generics ios swift

我有这个功能要从两个数字计算斜边

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

rob*_*off 5

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
Run Code Online (Sandbox Code Playgroud)

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

func hypotenusa(a: Float, b: Float) -> Float
func hypotenusa(a: Double, b: Double) -> Double
func hypotenusa(a: CGFloat, b: CGFloat) -> CGFloat
Run Code Online (Sandbox Code Playgroud)

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

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

func hypot(_: Double, _: Double) -> Double
func hypot(lhs: Float, rhs: Float) -> Float
Run Code Online (Sandbox Code Playgroud)

您可以创建另一个覆盖CGFloat

func hypot(l: CGFloat, r: CGFloat) -> CGFloat {
    return hypot(Double(l), Double(r))
}
Run Code Online (Sandbox Code Playgroud)

至于你的addition函数,它和你的函数有同样的问题hypotenusa+运算符不是完全通用的。它有一些通用定义(与sqrt和不同pow),但这些定义仅涵盖整数类型(请参阅 参考资料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
Run Code Online (Sandbox Code Playgroud)


Ima*_*tit 5

With Swift 5, according to your needs, you can pick one of the following ways in order to solve your problem.


#1. Using FloatingPoint protocol as a parameter generic constraint

The Apple Developer Documentation for FloatingPoint shows the following hypotenuse function implementation as an example of FloatingPoint usage:

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
Run Code Online (Sandbox Code Playgroud)

#2. Using AdditiveArithmetic protocol as a parameter generic constraint

AdditiveArithmetic has the following declaration:

A type with values that support addition and subtraction.

The Playground sample code below shows a possible usage of AdditiveArithmetic as a function parameter generic constraint:

func addition<T: AdditiveArithmetic>(a: T, b: T) -> T {
    return a + b
}

let result = addition(a: 3, b: 4)
print(result) // prints: 7
Run Code Online (Sandbox Code Playgroud)

#3. Using Numeric protocol as a parameter generic constraint

Numeric has the following declaration:

A type with values that support multiplication.

The Playground sample code below shows a possible usage of Numeric as a function parameter generic constraint:

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
Run Code Online (Sandbox Code Playgroud)

Note that Numeric protocol inherit from AdditiveArithmetic protocol.


The Apple Developer Documentation contains a dedicated page for all numeric protocols: Numeric Protocols.