Что такое оператор ~> (тильда больше, чем), используемый в Swift?

Swift 1.1 включает объявление оператора ~ > :

infix operator ~> {
    associativity left
    precedence 255
}

Для чего это используется в Swift? Он, как представляется, объявлен, но не определены функции, которые используют его. Другие разработчики использовали его для реактивных шаблонов и для маршалирования замыканий между очередями, но мне интересно, почему это определено в стандартной структуре. Я предполагаю, что он "резервирует" пользовательский оператор для использования разработчиком, учитывая, что он имеет наивысший приоритет.

Ответ 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: все специализации с использованием этого метода были изменены для использования расширений протокола, что более очевидно, например.


Примечание. Проблема радара 14011860 не является общедоступной, но мы можем увидеть масштаб ошибки по ее дубликатам на OpenRadar:

Ответ 2

Кажется, он связан с типами коллекции/последовательности/индекса

Согласно Defines-Swift:

protocol SequenceType : _Sequence_Type {
  typealias Generator : GeneratorType
  func generate() -> Generator
  func ~>(_: Self, _: (_UnderestimateCount, ())) -> Int
  func ~><R>(_: Self, _: (_PreprocessingPass, ((Self) -> R))) -> R?
  func ~>(_: Self, _: (_CopyToNativeArrayBuffer, ())) -> _ContiguousArrayBuffer<Self.Generator.Element>
}

protocol CollectionType : _CollectionType, SequenceType {
  subscript (position: Self.Index) -> Self.Generator.Element { get }
  func ~>(_: Self, _: (_CountElements, ())) -> Self.Index.Distance
}

protocol ForwardIndexType : _ForwardIndexType {
  func ~>(start: Self, _: (_Distance, Self)) -> Self.Distance
  func ~>(start: Self, _: (_Advance, Self.Distance)) -> Self
  func ~>(start: Self, _: (_Advance, (Self.Distance, Self))) -> Self
}

protocol SignedNumberType : _SignedNumberType {
  prefix func -(x: Self) -> Self
  func ~>(_: Self, _: (_Abs, ())) -> Self
}

func ~><T : _CollectionType>(x: T, _: (_CountElements, ())) -> T.Index.Distance
func ~><T : _CollectionType>(x: T, _: (_UnderestimateCount, ())) -> Int
func ~><T : _CollectionType, R>(s: T, args: (_PreprocessingPass, ((T) -> R))) -> R?
func ~><T : _SequenceType>(s: T, _: (_UnderestimateCount, ())) -> Int
func ~><T : _SequenceType, R>(s: T, _: (_PreprocessingPass, ((T) -> R))) -> R?
func ~><S : _Sequence_Type>(source: S, _: (_CopyToNativeArrayBuffer, ())) -> _ContiguousArrayBuffer<S.Generator.Element>
func ~><C : CollectionType where C._Element == C._Element>(source: C, _: (_CopyToNativeArrayBuffer, ())) -> _ContiguousArrayBuffer<C._Element>
func ~><T>(x: EmptyCollection<T>, _: (_CountElements, ())) -> Int
func ~><T : _ForwardIndexType>(start: T, rest: (_Distance, T)) -> T.Distance
func ~><T : _ForwardIndexType>(start: T, rest: (_Advance, T.Distance)) -> T
func ~><T : _ForwardIndexType>(start: T, rest: (_Advance, (T.Distance, T))) -> T
func ~><T : _BidirectionalIndexType>(start: T, rest: (_Advance, T.Distance)) -> T
func ~><T : _BidirectionalIndexType>(start: T, rest: (_Advance, (T.Distance, T))) -> T
func ~><T : _RandomAccessIndexType>(start: T, rest: (_Distance, (T))) -> T.Distance
func ~><T : _RandomAccessIndexType>(start: T, rest: (_Advance, (T.Distance))) -> T
func ~><T : _RandomAccessIndexType>(start: T, rest: (_Advance, (T.Distance, T))) -> T
func ~><T : _SignedNumberType>(x: T, _: (_Abs, ())) -> T
func ~><T : AbsoluteValuable>(x: T, _: (_Abs, ())) -> T
func ~><T>(x: CollectionOfOne<T>, _: (_CountElements, ())) -> Int

Например,

42 ~> _advance(12) // -> 54
42 ~> _distanceTo(23) // -> -19

Я не знаю, как они используются: -/

Ответ 3

В SwiftDoc этот оператор был удален из главы операторов для Swift 3.0.