我正在尝试为所有数字类型编写通用的半函数:
func half<T where T: FloatingPointType>(value: T) -> T { return value * 0.5 }
我看到这个错误:
No ‘*’ candidates produce the expected contextual result type ‘T’
在这种情况下是否可以编写泛型函数?
您编写“所有数字类型”,但基于0.5乘法,此答案基于您引用常用浮点类型(Double,Float,CGFloat)的假设.
原文链接:https://www.f2er.com/swift/319241.html您可以创建一个自定义协议,用于蓝图*函数(用于乘以Self的值)以及FloatLiteralType的初始化程序,并使Double,Float和CGFloat符合此协议. *函数和初始化器已经针对这三种类型实现,因此一致性只是明确地告诉编译器这些类型确实符合您的自定义协议.
例如.
protocol MyFloatingPointTypes { func *(lhs: Self,rhs: Self) -> Self init(_: FloatLiteralType) } extension Double : MyFloatingPointTypes {} extension Float : MyFloatingPointTypes {} extension CGFloat : MyFloatingPointTypes {} func half<T: MyFloatingPointTypes>(value: T) -> T { return value * T(0.5) } /* example usage */ var dVal: Double = 10.5 var fVal: Float = 10.5 var cfVal: CGFloat = 10.5 dVal = half(dVal) fVal = half(fVal) cfVal = half(cfVal) print(dVal,fVal,cfVal) // 5.25 5.25 5.25
替代方案:使用FloatLiteralConvertible进行复合协议约束
正如@Hamish在下面的评论中写道,而不是通过MyFloatingPointTypes中的Double(init(_:FloatLiteralType))对初始化程序进行蓝图打印,更好的方法是在通用half(…)函数中添加一个额外的类型约束,从而约束泛型(除了MyFloatingPointTypes)到FloatLiteralConvertible:
// lets rename this protocol here,since it no longer has any direct association with floats protocol Multiplicable { func *(lhs: Self,rhs: Self) -> Self } extension Double : Multiplicable {} extension Float : Multiplicable {} extension CGFloat : Multiplicable {} func half<T: protocol<Multiplicable,FloatLiteralConvertible>>(value: T) -> T { return value * 0.5 } /* example usage */ // ... same as above
另一种(更一般的)替代方法:复合协议约束,使用IntegerLiteralConvertible
或者,如果您希望半功能将其通用“覆盖”扩展为整数类型(也由@Hamish指出,谢谢!)您可以使用与上面相同的复合协议约束方法,但针对IntegerLiteralConvertible:
protocol Divisable { func /(lhs: Self,rhs: Self) -> Self } extension Double : Divisable {} extension Float : Divisable {} extension CGFloat : Divisable {} extension Int: Divisable {} func half<T: protocol<Divisable,IntegerLiteralConvertible>>(value: T) -> T { return value / 2 } /* example usage */ var dVal: Double = 10.5 var fVal: Float = 10.5 var cfVal: CGFloat = 10.5 var iVal: Int = 11 dVal = half(dVal) fVal = half(fVal) cfVal = half(cfVal) iVal = half(iVal) // truncates decimal part print(dVal,cfVal,iVal) // 5.25 5.25 5.25 5