Swift中的通用半功能

时间:2016-08-10 13:56:06

标签: swift

我试图为所有数字类型编写通用半函数:

func half<T where T: FloatingPointType>(value: T) -> T
{
    return value * 0.5
}

我看到了这个错误:

  

否&#39; *&#39;候选人产生预期的上下文结果类型&#39; T&#39;

在这种情况下是否可以编写泛型函数?

2 个答案:

答案 0 :(得分:7)

不在Swift 2.2中。 FloatingPointType不是一个非常强大的类型。在Swift 3中,如果您将自己限制在BinaryFloatingPoint(这涵盖了您可能正在考虑的大多数浮点类型,尤其是FloatDouble),这是可能的。

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} },DoubleFloat)。

您可以创建一个自定义协议,将CGFloat函数(用于乘以*的值)以及Self的初始值设定为蓝图,并符合FloatLiteralType,此协议DoubleFloatCGFloat函数以及初始化函数已经针对这三种类型实现,因此一致性只是明确地告诉编译器这些类型确实符合您的自定义协议。

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