Поиск…


Пользовательские операторы

Swift поддерживает создание пользовательских операторов. Новые операторы объявляются на глобальном уровне с использованием ключевого слова operator .

Структура оператора определяется тремя частями: размещение операндов, приоритет и ассоциативность.

  1. Модификаторы prefix , infix и postfix используются для запуска пользовательской декларации оператора. Модификаторы prefix и postfix объявляют, должен ли оператор быть до или после, соответственно, значением, на котором он действует. Такие операторы норны, как 8 и 3++ ** , поскольку они могут действовать только на одну цель. infix объявляет двоичный оператор, который действует на два значения между ними, например 2+3 .

  2. Сначала вычисляются операторы с более высоким приоритетом . По умолчанию приоритет оператора выше ? ... : (значение 100 в Swift 2.x). Очередность стандартных операторов Swift можно найти здесь .

  3. Ассоциативность определяет порядок операций между операторами с одинаковым приоритетом. Левые ассоциативные операторы вычисляются слева направо (порядок чтения, как и большинство операторов), а правые ассоциативные операторы вычисляют справа налево.

3.0

Начиная с Swift 3.0, можно определить приоритет и ассоциативность в группе приоритетов вместо самого оператора, так что несколько операторов могут легко использовать одинаковый приоритет, не обращаясь к загадочным номерам. Список стандартных групп приоритетов показан ниже .

Операторы возвращают значения на основе кода расчета. Этот код действует как нормальная функция с параметрами, определяющими тип ввода и ключевое слово return определяющее вычисленное значение, возвращаемое оператором.

Вот определение простого экспоненциального оператора, так как стандартный Swift не имеет экспоненциального оператора.

import Foundation    

infix operator ** { associativity left precedence 170 }

func ** (num: Double, power: Double) -> Double{
    return pow(num, power)
}

infix говорит, что оператор ** работает между двумя значениями, такими как 9**2 . Поскольку функция оставила ассоциативность, 3**3**2 вычисляется как (3**3)**2 . Приоритет 170 выше всех стандартных операций Swift, что означает, что 3+2**4 вычисляет до 19 , несмотря на левую ассоциативность ** .

3.0
import Foundation 

infix operator **: BitwiseShiftPrecedence

func ** (num: Double, power: Double) -> Double {
    return pow(num, power)
}

Вместо того, чтобы явно указывать приоритет и ассоциативность, в Swift 3.0 мы могли бы использовать встроенную группу приоритетов BitwiseShiftPrecedence, которая дает правильные значения (такие же, как << , >> ).

**: Приращение и декремент устарели и будут удалены в Swift 3.

Перегрузка + для словарей

Поскольку в настоящее время нет простого способа комбинирования словарей в Swift, может быть полезно перегрузить операторы + и += , чтобы добавить эту функциональность с помощью дженериков .

// Combines two dictionaries together. If both dictionaries contain
// the same key, the value of the right hand side dictionary is used.
func +<K, V>(lhs: [K : V], rhs: [K : V]) -> [K : V] {
    var combined = lhs
    for (key, value) in rhs {
        combined[key] = value
    }
    return combined
}

// The mutable variant of the + overload, allowing a dictionary
// to be appended to 'in-place'.
func +=<K, V>(inout lhs: [K : V], rhs: [K : V]) {
    for (key, value) in rhs {
        lhs[key] = value
    }
}
3.0

Начиная с Swift 3, inout следует помещать перед типом аргумента.

func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... } 

Пример использования:

let firstDict = ["hello" : "world"]
let secondDict = ["world" : "hello"]
var thirdDict = firstDict + secondDict // ["hello": "world", "world": "hello"]

thirdDict += ["hello":"bar", "baz":"qux"] // ["hello": "bar", "baz": "qux", "world": "hello"]

Коммутативные операторы

Давайте добавим пользовательский оператор для умножения CGSize

func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
    let height = lhs*rhs.height
    let width = lhs*rhs.width
    return CGSize(width: width, height: height)
}

Теперь это работает

let sizeA = CGSize(height:100, width:200)    
let sizeB = 1.1 * sizeA         //=> (height: 110, width: 220)

Но если мы попытаемся сделать операцию в обратном порядке, мы получим ошибку

let sizeC = sizeB * 20          // ERROR

Но достаточно просто добавить:

func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
    return rhs*lhs
}

Теперь оператор коммутативен.

let sizeA = CGSize(height:100, width:200)    
let sizeB = sizeA * 1.1              //=> (height: 110, width: 220)

Побитовые операторы

Быстрые операторы Swift позволяют выполнять операции над двоичной формой чисел. Вы можете указать бинарный литерал, предварительно 0b110 номер 0b , поэтому, например, 0b110 эквивалентен двоичному номеру 110 (десятичное число 6). Каждый 1 или 0 бит в числе.

Побитовое NOT ~ :

var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100

Здесь каждый бит изменяется на противоположное. Объявление числа как явно UInt8 гарантирует, что число положительно (так что нам не нужно иметь дело с негативами в примере) и что это всего 8 бит. Если 0b01101100 был большим UInt, то были бы ведущие 0s, которые были бы преобразованы в 1s и стали значительными при инверсии:

var number: UInt16 = 0b01101100
// number equals 0b0000000001101100
// the 0s are not significant
let newNumber = ~number
// newNumber equals 0b1111111110010011
// the 1s are now significant
  • 0 -> 1
  • 1 -> 0

Побитовое И & :

var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010

Здесь данный бит будет равен 1, если и только если двоичные числа с обеих сторон оператора & содержали 1 в этом месте бит.

  • 0 & 0 -> 0
  • 0 & 1 -> 0
  • 1 & 1 -> 1

Побитовое ИЛИ | :

var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110

Здесь данный бит будет равен 1, если и только если двоичное число, по крайней мере, на одной стороне | оператор содержал 1 в этом месте бит.

  • 0 | 0 -> 0
  • 0 | 1 -> 1
  • 1 | 1 -> 1

Побитовое XOR (Исключительное ИЛИ) ^ :

var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100

Здесь данный бит будет равен 1, если и только если бит в этом положении двух операндов отличается.

  • 0 ^ 0 -> 0
  • 0 ^ 1 -> 1
  • 1 ^ 1 -> 0

Для всех двоичных операций порядок операндов не влияет на результат.

Операторы переполнения

Переполнение относится к тому, что происходит, когда операция приведет к числу, которое больше или меньше, чем указанное количество бит для этого числа может удерживаться.

Из-за того, как работает двоичная арифметика, после того, как число становится слишком большим для своих битов, число переполняется до наименьшего возможного числа (для размера бита), а затем продолжает подсчитывать оттуда. Точно так же, когда число становится слишком маленьким, оно переполняется до максимально возможного числа (для его размера бит) и продолжает отсчет оттуда.

Поскольку это поведение часто не требуется и может привести к серьезным проблемам безопасности, операторы арифметики Swift + , - и * будут вызывать ошибки, когда операция приведет к переполнению или потоку. Чтобы явно разрешить переполнение и недоиспользование, вместо этого используйте &+ , &- и &* .

var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min

Приоритет стандартных операторов Swift

В первую очередь перечисляются операторы, которые связаны более строгим (более высокий приоритет).

операторы Группа приоритетов (≥ 3,0) старшинство Ассоциативность
. оставил
? , ! , ++ , -- , [] , () , {} (Постфиксный)
! , ~ , + , - , ++ , -- (префикс)
~> (быстрый ≤2.3) 255 оставил
<< , >> BitwiseShiftPrecedence 160 никто
* , / , % , & , &* MultiplicationPrecedence 150 оставил
+ , - , | , ^ , &+ , &- AdditionPrecedence 140 оставил
... , ..< RangeFormationPrecedence 135 никто
is , as , as? , as! CastingPrecedence 132 оставил
?? NilCoalescingPrecedence 131 право
< , <= , > , >= , == != , === !== , ~= ComparisonPrecedence 130 никто
&& LogicalConjunctionPrecedence 120 оставил
|| LogicalDisjunctionPrecedence 110 оставил
DefaultPrecedence * никто
? ... : TernaryPrecedence 100 право
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= AssignmentPrecedence 90 право, назначение
-> FunctionArrowPrecedence право
3.0
  • Группа приоритетов DefaultPrecedence выше, чем TernaryPrecedence , но не упорядочена с остальными операторами. Помимо этой группы, остальные приоритеты линейны.


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow