我正在Swift中构建一个通用向量类,有三种类型:Float,Double和Int。到目前为止这是有效的,但是当我尝试计算向量的长度时,我遇到了一个问题。
向量长度的公式是(x²+y²)的平方根。但是因为我为我的向量使用泛型类,所以x和y的值被称为T.
Swift的sqrt函数只接受Double作为参数但不接受泛型参数。
有没有办法将sqrt函数与泛型参数一起使用?
以下是我用于矢量长度和点积的代码片段:
protocol ArithmeticType {
func + (left: Self, right: Self) -> Self
func - (left: Self, right: Self) -> Self
func * (left: Self, right: Self) -> Self
func / (left: Self, right: Self) -> Self
prefix func - (left: Self) -> Self
func toDouble() -> Double
}
extension Double: ArithmeticType {
func toDouble() -> Double {
return Double(self)
}
}
extension Float: ArithmeticType {
func toDouble() -> Double {
return Double(self)
}
}
extension Int: ArithmeticType {
func toDouble() -> Double {
return Double(self)
}
}
class Vector<T where T: ArithmeticType, T: Comparable> {
var length: T { return sqrt((self ⋅ self).toDouble()) }
}
infix operator ⋅ { associativity left }
func ⋅<T: ArithmeticType> (left: Vector<T>, right: Vector<T>) -> T {
var result: T? = nil
for (index, value) in enumerate(left.values) {
let additive = value * right.values[index]
if result == nil {
result = additive
} else if let oldResult = result {
result = oldResult + additive
}
}
if let unwrappedResult = result {
return unwrappedResult
}
}
答案 0 :(得分:2)
在Swift 3中,只需使用属于标准库而不是FloatingPoint
协议的ArithmeticType
协议。 Float
和Double
符合FloatingPoint
协议。 FlotingPoint
协议有一个squareRoot()
方法,所以
class Vector<T where T: FloatingPoint> {
var length: T { return (self ⋅ self).squareRoot() }
}
应该这样做。
无需导入任何库或进行任何运行时类型检查!调用此方法会变成内置的LLVM,因此甚至没有任何函数调用开销。在x86上,sqareRoot()应该只生成一个机器语言指令,将结果保留在寄存器中以便复制return语句。
答案 1 :(得分:1)
我发现您正在使用自定义Arithmetic
协议来约束通用。
我的方法是在该协议中声明2个必需的方法:toDouble()
和fromDouble()
,并在Float
,Double
和Int
扩展中实现。请注意,fromDouble()
应该是静态方法。
这样您就可以将T
转换为Double
,从而能够使用sqrt()
,并从Double
转换回T
。
最后,您的代码中存在一个错误:如果left
是一个空向量,该函数将崩溃,因为循环中的代码永远不会被执行,因此result
将保持不变其nil
初始值。 return
语句中的强制解包将失败,从而导致异常。
答案 2 :(得分:0)
Swift中没有通用的sqrt。但你可以制作自己的通用。
tuple