Swift Language
Расширенные операторы
Поиск…
Пользовательские операторы
Swift поддерживает создание пользовательских операторов. Новые операторы объявляются на глобальном уровне с использованием ключевого слова operator .
Структура оператора определяется тремя частями: размещение операндов, приоритет и ассоциативность.
Модификаторы
prefix,infixиpostfixиспользуются для запуска пользовательской декларации оператора. Модификаторыprefixиpostfixобъявляют, должен ли оператор быть до или после, соответственно, значением, на котором он действует. Такие операторы норны, как8и3++** , поскольку они могут действовать только на одну цель.infixобъявляет двоичный оператор, который действует на два значения между ними, например2+3.Сначала вычисляются операторы с более высоким приоритетом . По умолчанию приоритет оператора выше
?...:(значение 100 в Swift 2.x). Очередность стандартных операторов Swift можно найти здесь .Ассоциативность определяет порядок операций между операторами с одинаковым приоритетом. Левые ассоциативные операторы вычисляются слева направо (порядок чтения, как и большинство операторов), а правые ассоциативные операторы вычисляют справа налево.
Начиная с 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 , несмотря на левую ассоциативность ** .
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
}
}
Начиная с 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 | право |
- Группа приоритетов
DefaultPrecedenceвыше, чемTernaryPrecedence, но не упорядочена с остальными операторами. Помимо этой группы, остальные приоритеты линейны.
- Эту таблицу можно также найти в справочной системе Apple API
- Фактическое определение групп приоритетов можно найти в исходном коде GitHub