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

Posted

技术标签:

【中文标题】如何只接受在 Swift 中使用泛型的运算符的数字?【英文标题】:How To Only Accept Numbers For An Operator Using Generics In Swift? 【发布时间】:2015-07-04 06:56:21 【问题描述】:

我正在尝试为数字创建一个运算符。例如一个将数字加 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

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

【问题讨论】:

Nuneric 是一种没有要求的协议。我认为当您将func +(lhs: Self, rhs: Self) -&gt; Self 放入您的协议时它应该可以工作 @Kametrixom 你还需要IntegerLiteralConvertible 这样你就可以创建一个合适类型的“10”。 【参考方案1】:

这是一种更清洁、更好的方法,适用于从 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

【讨论】:

这其实是真正的泛型。 考虑根据问题要求返回operand 由于Strideable.StrideIntegerLiteralConvertible,所以你可以像prefix func +++&lt;T: Strideable&gt;(inout operand: T) -&gt; T operand = operand.advancedBy(10); return operand 一样一键搞定【参考方案2】:

问题是您的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 

【讨论】:

您在 func 声明中缺少前缀关键字 这就是我所需要的。谢谢。还有一件事。你从哪里学来的这些?在其他情况下,我如何自己解决问题?没有关于 StrideableIntegerLiteralConverible 的文档。 :| 标准库(定义这些协议的地方)文档可以在here 找到 - 这是今年六月的新事物。您过去必须通过在操场上通过命令单击诸如 Int 之类的东西来查找内容,以查看 std lib 标头。 SwiftDoc 也很好,因为它有层次结构图——查看像 Int 这样的协议类型实现了哪些功能通常很有用。 从现在开始,你就是我的超级英雄。非常非常感谢你。 :-*

以上是关于如何只接受在 Swift 中使用泛型的运算符的数字?的主要内容,如果未能解决你的问题,请参考以下文章

Swift泛型的使用

Type 应该采用啥协议来让泛型函数将任何数字类型作为 Swift 中的参数?

OC的泛型使用介绍

具有泛型的Swift函数,其中约束是自身符合的协议

Java8基础知识泛型的约束与局限性

Java泛型学习笔记 - 泛型的介绍