Ответ 1
Так как Swift был открыт с открытым исходным кодом, мы можем увидеть фактическую причину включения ~>
в stdlib: в качестве обходного пути для специализации метода в дочернем протокол в Swift 1.x.
// Workaround for <rdar://problem/14011860> SubTLF: Default
// implementations in protocols. Library authors should ensure
// that this operator never needs to be seen by end-users. See
// test/Prototypes/GenericDispatch.swift for a fully documented
// example of how this operator is used, and how its use can be hidden
// from users.
infix operator ~> { associativity left precedence 255 }
Подробный пример можно найти в test/Prototypes/GenericDispatch.swift.
Примечание: Не используйте ~>
в Swift 2 +. Это историческое обходное решение. Он больше не нужен. Читайте дальше.
Как ~>
работает
В Swift 2 единственным оставшимся экземпляром ~>
является функция abs
(которая, вероятно, тоже уходит). Мы видим, как работает ~>
. Из stdlib/public/core/IntegerArithmetic.swift.gyb протокол SignedInteger
определяет оператор ~>
:
struct _Abs {}
protocol SignedNumber: Comparable {
prefix func -(_: Self) -> Self
func ~> (_: Self, _: (_Abs, ()) -> Self
}
func ~> <T: SignedNumber>(x: T, _: (_Abs, ()) -> T {
return x < 0 ? -x : x
}
Здесь RHS стрелки ~>
указывает, какую команду можно отправить объекту. Подумайте о p~>(cmd, args)
как о чем-то вроде p.cmd(args)
.
Затем мы предоставляем реализацию по умолчанию _Abs
при задании SignedNumber
.
protocol AbsoluteValuable : SignedNumber {
static func abs(_: Self) -> Self
}
func ~> <T: AbsoluteValuable>(x: T, _: (_Abs, ())) -> T {
return T.abs(x)
}
Далее у нас есть дочерний протокол AbsoluteValuable
, который, возможно, имеет более эффективный способ вычисления абсолютного значения, чем x < 0 ? -x : x
. Затем мы специализируем оператор ~>
для AbsoluteValuable
.
func abs<T: SignedNumber>(_ x: T) -> T {
return x ~> (_Abs(), ())
}
Наконец, мы скрываем вызов ~>
в общедоступном методе обертки. Если T
на самом деле является AbsoluteValuable
, будет выбран более специализированный и, следовательно, более эффективный ~>
.
Вот почему мы получаем 42 ~> _advance(12)
или 42 ~> _distanceTo(23)
, как показано в @rintaro answer, потому что методы .advanceBy
и .distanceTo
- это O ( n) для общего ForwardIndexType
, но может быть реализовано в O (1), если тип RandomAccessIndexType
.
Вам не нужно ~>
Этот шаблон также можно выполнить без вызова оператора ~>
с использованием расширений в протоколе:
protocol SignedInteger: Comparable {
prefix func -(_: Self) -> Self
func genericAbs() -> Self
}
extension SignedInteger {
func genericAbs() -> Self {
return self < 0 ? -self : self
}
}
protocol AbsoluteValueable: SignedInteger {
static func abs(_: Self) -> Self
}
extension AbsoluteValueable {
func genericAbs() -> Self {
return Self.abs(self)
}
// normally you would allow subtypes to override
// genericAbs() directly, instead of overriding
// static abs().
}
func abs<T: SignedInteger>(x: T) -> T {
return x.genericAbs()
}
В частности, поэтому все остальные реализации ~>
, кроме abs
, ушли в Swift 2: все специализации с использованием этого метода были изменены для использования расширений протокола, что более очевидно, например.
-
underestimateCount
в совершить c48d6aa0 (2015 16 апреля) -
advancedBy
,distanceTo
в commit 311baf73 (2015 Aug 4) - и др.
Примечание. Проблема радара 14011860 не является общедоступной, но мы можем увидеть масштаб ошибки по ее дубликатам на OpenRadar: