Swift Language
Zaawansowani operatorzy
Szukaj…
Operatorzy niestandardowi
Swift obsługuje tworzenie niestandardowych operatorów. Nowi operatorzy są deklarowani na poziomie globalnym za pomocą słowa kluczowego operator
.
Strukturę operatora definiują trzy części: umiejscowienie operandu, pierwszeństwo i asocjatywność.
Modyfikatory
prefix
,infix
ipostfix
służą do uruchamiania niestandardowej deklaracji operatora. Modyfikatoryprefix
ipostfix
deklarują, czy operator musi być odpowiednio przed, czy po wartości, na którą działa. Takie operatory są pilne, jak8
i3++
** , ponieważ mogą działać tylko na jednym celu.infix
deklaruje operator binarny, który działa na dwie wartości, między którymi się znajduje, takie jak2+3
.Operatory o wyższym priorytecie są obliczane w pierwszej kolejności. Domyślny priorytet operatora jest tylko wyższy niż
?
...:
(wartość 100 w Swift 2.x). Pierwszeństwo standardowych operatorów Swift można znaleźć tutaj .Asocjatywność określa kolejność operacji między operatorami o tym samym priorytecie. Lewe operatory asocjacyjne są obliczane od lewej do prawej (kolejność odczytu, jak większość operatorów), podczas gdy operatory prawe asocjacyjne obliczają od prawej do lewej.
Począwszy od Swift 3.0, zamiast samego operatora można zdefiniować pierwszeństwo i skojarzenie w grupie pierwszeństwa , tak aby wielu operatorów mogło z łatwością dzielić ten sam priorytet bez odwoływania się do tajemniczych liczb. Lista standardowych grup pierwszeństwa jest pokazana poniżej .
Operatorzy zwracają wartości na podstawie kodu obliczeniowego. Ten kod działa jak normalna funkcja z parametrami określającymi typ danych wejściowych i słowem kluczowym return
określającym obliczoną wartość zwracaną przez operatora.
Oto definicja prostego operatora wykładniczego, ponieważ standardowy Swift nie ma operatora wykładniczego.
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
infix
mówi, że operator **
działa pomiędzy dwiema wartościami, takimi jak 9**2
. Ponieważ funkcja pozostawiła skojarzenie, 3**3**2
oblicza się jako (3**3)**2
. Priorytet 170
jest wyższy niż wszystkie standardowe operacje Swift, co oznacza, że 3+2**4
oblicza do 19
, pomimo lewego skojarzenia **
.
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
Zamiast jawnego określenia pierwszeństwa i powiązania, w Swift 3.0 moglibyśmy użyć wbudowanej grupy pierwszeństwa BitwiseShiftPrecedence, która daje prawidłowe wartości (takie same jak <<
, >>
).
**: Przyrost i spadek są przestarzałe i zostaną usunięte w Swift 3.
Przeciążenie + dla słowników
Ponieważ w Swift nie ma obecnie prostego sposobu łączenia słowników, przydatne może być przeciążenie operatorów +
i +=
w celu dodania tej funkcji za pomocą ogólnych .
// 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
}
}
Począwszy od wersji Swift 3, inout
powinno być umieszczone przed typem argumentu.
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
Przykładowe użycie:
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"]
Operatory przemienne
Dodajmy niestandardowego operatora, aby pomnożyć CGSize
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
Teraz to działa
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
Ale jeśli spróbujemy wykonać operację w odwrotnej kolejności, otrzymamy błąd
let sizeC = sizeB * 20 // ERROR
Ale wystarczy dodać:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
Teraz operator jest przemienny.
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
Operatory bitowe
Szybkie operatory bitowe umożliwiają wykonywanie operacji na binarnej postaci liczb. Możesz podać literał binarny, poprzedzając cyfrę 0b
, więc na przykład 0b110
jest równoważne liczbie binarnej 110 (liczba dziesiętna 6). Każde 1 lub 0 jest trochę w liczbie.
Bitowe NIE ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
Tutaj każdy bit zmienia się na przeciwny. Zadeklarowanie liczby jako jawnej UInt8
zapewnia, że liczba jest dodatnia (dzięki czemu nie mamy do czynienia z negatywami w tym przykładzie) i że jest to tylko 8 bitów. Gdyby 0b01101100
był większym UIntem, istniałyby wiodące zera, które zostałyby przekonwertowane na 1 i stałyby się znaczące po odwróceniu:
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
Bitowe ORAZ &
:
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
W tym przypadku dany bit będzie wynosił 1, jeśli tylko liczby binarne po obu stronach operatora &
zawierają 1 w tym miejscu.
- 0 i 0 -> 0
- 0 i 1 -> 0
- 1 i 1 -> 1
Bitowe LUB |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
Tutaj dany bit będzie wynosił 1 wtedy i tylko wtedy, gdy liczba binarna po co najmniej jednej stronie |
operator zawierał 1 w tym miejscu bitowym.
- 0 | 0 -> 0
- 0 | 1 -> 1
- 1 | 1 -> 1
Bitowy XOR (wyłączny LUB) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
Tutaj dany bit będzie wynosił 1, jeśli tylko bity w tej pozycji dwóch argumentów są różne.
- 0 ^ 0 -> 0
- 0 ^ 1 -> 1
- 1 ^ 1 -> 0
Dla wszystkich operacji binarnych kolejność operandów nie ma wpływu na wynik.
Operatorzy przepełnienia
Przepełnienie odnosi się do tego, co dzieje się, gdy operacja spowodowałaby, że liczba jest większa lub mniejsza niż wyznaczona ilość bitów dla tej liczby.
Ze względu na sposób działania arytmetyki binarnej, gdy liczba staje się zbyt duża dla swoich bitów, liczba przelewa się do najmniejszej możliwej liczby (dla rozmiaru bitu), a następnie kontynuuje liczenie od tego momentu. Podobnie, gdy liczba staje się zbyt mała, przepełnia się do największej możliwej liczby (ze względu na swój rozmiar bitów) i odtąd kontynuuje odliczanie.
Ponieważ takie zachowanie nie jest często pożądane i może prowadzić do poważnych problemów związanych z bezpieczeństwem, operatory arytmetyczne Swift +
, -
i *
będą zgłaszać błędy, gdy operacja spowoduje przepełnienie lub niedopełnienie. Aby jawnie zezwolić na przepełnienie i niedopełnienie, użyj zamiast tego &+
, &-
i &*
.
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
Pierwszeństwo standardowych operatorów Swift
Operatorzy, którzy związali się ściślej (wyższy priorytet) są wymienieni jako pierwsi.
Operatorzy | Grupa pierwszeństwa (≥3,0) | Precedens | Stowarzyszenie |
---|---|---|---|
. | ∞ | lewo | |
? , ! , ++ , -- , [] , () , {} | (przyrostek) | ||
! , ~ , + , - , ++ , -- | (prefiks) | ||
~> (szybki ≤2,3) | 255 | lewo | |
<< , >> | BitwiseShiftPrecedence | 160 | Żaden |
* , / , % & &* | MnożeniePrecedens | 150 | lewo |
+ , - , | , ^ , &+ , &- | DodawaniePrecedens | 140 | lewo |
... , ..< | RangeFormationPrecedence | 135 | Żaden |
is , as , as? , as! | CastingPrecedence | 132 | lewo |
?? | NilCoalescingPrecedence | 131 | dobrze |
< , <= , > , >= , == != , === !== , ~= | PorównaniePrecedens | 130 | Żaden |
&& | LogicalConjunctionPrecedence | 120 | lewo |
|| | LogicalDisjunctionPrecedence | 110 | lewo |
DefaultPrecedence * | Żaden | ||
? ... : | Trójskładnikowy | 100 | dobrze |
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= | PrzydziałPrecedens | 90 | racja, zadanie |
-> | FunctionArrowPrecedence | dobrze |
- Grupa pierwszeństwa
DefaultPrecedence
jest wyższa niżTernaryPrecedence
, ale jest nieuporządkowana z resztą operatorów. Poza tą grupą pozostałe pierwszeństwa są liniowe.
- Tę tabelę można również znaleźć w dokumentacji API Apple
- Rzeczywistą definicję grup pierwszeństwa można znaleźć w kodzie źródłowym na GitHub