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