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ść.

  1. Modyfikatory prefix , infix i postfix służą do uruchamiania niestandardowej deklaracji operatora. Modyfikatory prefix i postfix deklarują, czy operator musi być odpowiednio przed, czy po wartości, na którą działa. Takie operatory są pilne, jak 8 i 3++ ** , 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 jak 2+3 .

  2. 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 .

  3. 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.

3.0

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 ** .

3.0
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
    }
}
3.0

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
3.0
  • 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.


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow