我试图为所有数字类型编写通用半函数:
func half<T where T: FloatingPointType>(value: T) -> T
{
return value * 0.5
}
我看到了这个错误:
否&#39; *&#39;候选人产生预期的上下文结果类型&#39; T&#39;
在这种情况下是否可以编写泛型函数?
答案 0 :(得分:7)
不在Swift 2.2中。 FloatingPointType
不是一个非常强大的类型。在Swift 3中,如果您将自己限制在BinaryFloatingPoint
(这涵盖了您可能正在考虑的大多数浮点类型,尤其是Float
和Double
),这是可能的。
func half<T where T: BinaryFloatingPoint>(_ value: T) -> T {
return value * 0.5
}
在Swift 2.2中自定义FloatingPointType
的最常见情况下,系统可能无法将此转换为Double
乘法,然后将其转换回您的FloatingPointType
BinaryFloatingPoint
}。 ExpressibleByFloatLiteral
协议添加了0.5
,这意味着0.5
可以转换为您的任意类型。
请务必注意,上述代码中的T
类型为Double
。它不是func half<T where T: BinaryFloatingPoint>(_ value: T) -> T {
let oneHalf = 0.5
return value * oneHalf
// error: binary operator '*' cannot be applied to operands of type 'T' and 'Double'
}
。以下代码仍然不起作用:
FloatingPoint
您不能将两个任意浮点数相乘。 Swift故意避免大量自动类型强制,这是C中微妙错误的根源。在自定义FloatingPoint
的一般情况下,不可能说一种类型比另一种类型“更准确”。它们在不同范围内可能具有不同的精度。当然,您可以创建一个比双倍大的@n int
。因此,没有明显的“只是推广一切可以加倍”的规则,你可以使用。
答案 1 :(得分:4)
您编写“所有数字类型”,但基于0.5
乘法,此答案基于您引用常用浮点类型的假设({{1} },Double
,Float
)。
您可以创建一个自定义协议,将CGFloat
函数(用于乘以*
的值)以及Self
的初始值设定为蓝图,并符合FloatLiteralType
,此协议Double
和Float
。 CGFloat
函数以及初始化函数已经针对这三种类型实现,因此一致性只是明确地告诉编译器这些类型确实符合您的自定义协议。
E.g。
*
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
正如@Hamish在下面的评论中写道,而不是FloatLiteralConvertible
Double
init(_: FloatLiteralType)
中的初始化程序蓝图,更好的方法是为通用添加额外的类型约束MyFloatingPointTypes
功能,将通用(除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
函数将其通用“coverage”扩展为整数类型(也由@Hamish指出,谢谢!)您可以使用与上述相同的复合协议约束方法,但反对half
:
IntegerLiteralConvertible