Как принимать номера только для оператора, использующего Generics в 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
}
Но это не удалось скомпилировать. У кого-нибудь есть идеи?
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
}
Вот гораздо чище и лучше и работает со всем от 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
}