FloatingPointType 协议确实被Double 和Float 类型采用,但相反,由于某种原因,该协议不包括蓝图运算符方法,例如(在您的情况下)、* 二元运算符或 += 赋值运算符。请注意,仅仅因为某些已知类型采用一个协议,该协议本身不一定包含我们对采用它的那些类型所期望的所有蓝图。
另一方面,IntegerType 协议确实包含运算符方法的蓝图。
因此,符合协议FloatingPointType 的通用T 不一定(在swift 眼中)是可乘的等等,因为协议不包含此类操作的蓝图。如果我们查看standard library reference for FloatingPointType,我们会发现它似乎仅被Double、Float(和CGFloat)采用。我们知道所有这三种类型都可以单独使用我们的常规运算符,所以嘿,为什么我们不能在符合FloatingPointType 的泛型上使用这些运算符?同样,符合协议的类型集合实际上并不能深入了解该协议包含的蓝图。
作为一个例子,看下面的协议扩展一些基本类型以符合它
protocol ReallyLotsOfAdditionalStuff {}
extension Int : ReallyLotsOfAdditionalStuff {}
extension Double : ReallyLotsOfAdditionalStuff {}
此虚拟协议的库参考将列出仅类型 Int 和 Double 采用它。相反,如果我们不小心,我们可能会认为符合协议 ReallyLotsOfAdditionalStuff 的泛型至少可以说是可添加的(除了许多额外的东西),但很自然,情况并非如此。
无论如何,您都可以自己解决这个问题,但是,您可以创建一个新协议,将其作为通用 T 的附加类型约束添加到您的 FloatingPointType 函数中。
protocol MyNecessaryFloatingPointTypeOperations {
func *(lhs: Self, rhs: Self) -> Self
func += (inout lhs: Self, rhs: Self)
// ... other necessary floating point operator blueprints ...
}
extension Float: MyNecessaryFloatingPointTypeOperations {}
extension Double: MyNecessaryFloatingPointTypeOperations {}
// Example: only type constraint to FloatingPointType
func errorFloatingPointType<T: FloatingPointType> (a: T, b: T) -> T {
return a * b // Error: binary operator '*' cannot be applied to two 'T' operands
}
// Example: additional type constraint to your custom protocol
func noErrorFloatingPointType<T: protocol<FloatingPointType, MyNecessaryFloatingPointTypeOperations>> (a: T, b: T) -> T {
return a * b // ok!
}
因此,要修复您的FloatingPointType,请将您的自定义协议添加为函数头中T 的附加类型约束:
func linconv<T: protocol<FloatingPointType, MyNecessaryFloatingPointTypeOperations>>(signal_A: [T], signal_B: [T]) -> [T]? {
// ...
}
或者,让您自己的协议继承 FloatingPointType 并向您的“子协议”添加所需的任何其他方法,例如:
protocol ImprovedFloatingPointType : FloatingPointType {
func *(lhs: Self, rhs: Self) -> Self
func += (inout lhs: Self, rhs: Self)
// ... other necessary integer and floating point blueprints
}
extension Float: ImprovedFloatingPointType {}
extension Double: ImprovedFloatingPointType {}
func linconv<T: ImprovedFloatingPointType>(signal_A: [T], signal_B: [T]) -> [T]? {
// ...
}
最后,我们可能会问,我们是否首先需要FloatingPointType 协议(甚至作为我们自定义协议的父协议)?如果我们只想制作一个泛型来处理Double 和Float 这两种快速浮点类型,那么我们不妨只应用协议MyNecessaryFloatingPointTypeOperations 作为泛型的类型约束:
func myFloatingPointGenericFunction<T: MyNecessaryFloatingPointTypeOperations> (a: T, b: T) -> T {
// ...
return a * b
}
您可能已经知道,对于单个蓝图,我们需要泛型符合FloatingPointType 协议:确定我们可以使用整数初始化器(即init(_ value: Int))初始化T 实例的泛型函数。例如,在你的函数中:
// new array for result
var resultSignal = [T](count: N, repeatedValue: T(0)) // <--
但是,如果这是我们在 FloatingPointType 协议中使用的唯一蓝图,我们不妨将其作为蓝图添加到我们自己的协议中,并完全删除对 FloatingPointType 的泛型类型约束。
protocol MyNecessaryFloatingPointTypeOperations {
func *(lhs: Self, rhs: Self) -> Self
func += (inout lhs: Self, rhs: Self)
init(_ value: Int)
// ... other necessary floating point blueprints
}
extension Float: MyNecessaryFloatingPointTypeOperations {}
extension Double: MyNecessaryFloatingPointTypeOperations {}
func myFloatingPointGenericFunction<T: MyNecessaryFloatingPointTypeOperations> (a: T, b: T) -> T {
// ...
var c = T(0) // OK
c += a * b // OK
return c
}
这样,我们意识到对于整数类型和浮点类型,我们真的不需要两个单独的泛型。因为我们(以你的例子)只需要 1。一个 by-int-initializer、2.* 二元运算符和 3.+= 赋值运算符,我们可以为所有符合这些蓝色标记的类型构造一个泛型作为类型约束,并扩展我们的类型希望被本协议的泛型覆盖。
protocol MyCustomProtocol {
func *(lhs: Self, rhs: Self) -> Self
func += (inout lhs: Self, rhs: Self)
init(_ value: Int)
// ... other necessary integer and floating point blueprints
}
extension Int: MyCustomProtocol {}
extension Float: MyCustomProtocol {}
extension Double: MyCustomProtocol {}
func myIntAndFloatGenericFunction<T: MyCustomProtocol> (a: T, _ b: T) -> T {
// ...
var c = T(0) // OK
c += a * b // OK
return c
}
let aInt = 2
let bInt = 3
let aInt32: Int32 = 2
let bInt32: Int32 = 3
let aDouble = 2.5
let bDouble = 3.0
let cInt = myIntAndFloatGenericFunction(aInt, bInt) // 6
let cInt32 = myIntAndFloatGenericFunction(aInt32, bInt32) // error
let cDouble = myIntAndFloatGenericFunction(aDouble, bDouble) // 7.5
然而,在这里,我们看到使用现有 IntegerType 协议的一个好处:它已经被许多整数类型采用,而对于我们的自定义协议,所有这些 int 类型(如果我们想在我们的泛型中使用它们) 需要明确扩展以采用我们的自定义协议。
总结一下:如果您明确知道泛型要涵盖哪些类型,您可能会编写自己的自定义协议并扩展这些类型以适应这一点。如果您想要所有(众多)不同的整数类型,可能更喜欢使用两个单独的整数和浮点数泛型,后者使用协议IntegerType。