如何只接受在 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) -> Self
放入您的协议时它应该可以工作
@Kametrixom 你还需要IntegerLiteralConvertible
这样你就可以创建一个合适类型的“10”。
【参考方案1】:
这是一种更清洁、更好的方法,适用于从 Int8
到 CGFloat
的所有内容,并且只使用标准库类型,因此您无需手动符合自己的协议:
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.Stride
是IntegerLiteralConvertible
,所以你可以像prefix func +++<T: Strideable>(inout operand: T) -> 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 声明中缺少前缀关键字 这就是我所需要的。谢谢。还有一件事。你从哪里学来的这些?在其他情况下,我如何自己解决问题?没有关于Strideable
或 IntegerLiteralConverible
的文档。 :|
标准库(定义这些协议的地方)文档可以在here 找到 - 这是今年六月的新事物。您过去必须通过在操场上通过命令单击诸如 Int
之类的东西来查找内容,以查看 std lib 标头。 SwiftDoc 也很好,因为它有层次结构图——查看像 Int
这样的协议类型实现了哪些功能通常很有用。
从现在开始,你就是我的超级英雄。非常非常感谢你。 :-*以上是关于如何只接受在 Swift 中使用泛型的运算符的数字?的主要内容,如果未能解决你的问题,请参考以下文章