如何仅接受 Swift 中使用泛型的运算符的数字?

How To Only Accept Numbers For An Operator Using Generics In Swift?

我正在尝试为数字创建一个运算符。例如,将数字递增 10 的运算符。

这是我写的代码:

prefix operator +++{}

prefix operator +++<T>(inout operand: T) -> T{
    operand += 10
    return operand
}

我的 += 运算符出错。它需要数字操作数。所以我这样做了:

protocol Numeric {}

extension Int: Numeric {}
extension Float: Numeric {}
extension Double: Numeric {}

prefix operator +++ {}

prefix operator +++<T: Numeric>(inout operand: T) -> T {
    operand += 10
    return operand
}

但是编译失败。有人有什么想法吗?

这是一种更简洁、更好的方法,适用于从 Int8CGFloat 的所有内容,并且仅使用标准库类型,因此您无需手动遵守自己的协议:

prefix operator +++ {}    
prefix func +++<T where T: FloatingPointType, T.Stride: FloatingPointType>(inout operand: T) -> T {
    operand = operand.advancedBy(T.Stride(10))
    return operand
}

prefix func +++<T where T: IntegerArithmeticType, T: IntegerLiteralConvertible, T.IntegerLiteralType: IntegerLiteralConvertible>(inout operand: T) -> T {
    operand = operand + T(integerLiteral: 10)
    return operand
}

正如@Airspeed Velocity 指出的那样,您也可以这样做:

prefix operator +++ {}
prefix func +++<T: Strideable>(inout operand: T) -> T {
    operand = operand.advancedBy(10)
    return operand
}

问题是您的 Numeric 协议不保证 += 操作员会出现。

考虑一下:

// Numeric imposes no requirements, so this will compile
extension Range: Numeric { }
// but Range has no += operator, so +++ could not work

相反,您必须添加 += 作为 Numeric 的要求:

protocol Numeric: IntegerLiteralConvertible {
    func +=(inout lhs: Self,rhs: Self)
}

请注意,您还需要 Numeric 符合 IntegerLiteralConvertible 以便您可以创建适当类型的 10 以添加到其中。

现在,编译并运行良好,因为 Numeric 保证它使用的所有功能都可用:

prefix operator +++{}

prefix func +++<T: Numeric>(inout operand: T) -> T {
    operand += 10
    return operand
}

var i = 10
+++i  // i is now 20

也就是说,已经有一个协议可以满足您的需求:Strideable,所有标准数字类型都遵循该协议。

protocol Strideable {
// (actually _Strideable but don’t worry about that)

    /// A type that can represent the distance between two values of `Self`.
    typealias Stride : SignedNumberType
    // note, SignedNumberType conforms to IntegerLiteralConvertible

    /// Returns a `Self` `x` such that `self.distanceTo(x)` approximates
    /// `n`.
    ///
    /// - Complexity: O(1).
    ///
    /// - SeeAlso: `RandomAccessIndexType`'s `advancedBy`, which
    ///   provides a stronger semantic guarantee.
    func advancedBy(n: Self.Stride) -> Self
}

以及使用它的 += 的实现:

func +=<T : Strideable>(inout lhs: T, rhs: T.Stride)

这意味着您可以像这样实现 +++

prefix func +++<T: Strideable>(inout operand: T) -> T { 
    operand = operand.advancedBy(10)
    return operand 
}