Swift Language
Geavanceerde operators
Zoeken…
Aangepaste operatoren
Swift ondersteunt het maken van aangepaste operators. Nieuwe operators worden op mondiaal niveau gedeclareerd met behulp van het operator
.
De structuur van de operator wordt bepaald door drie delen: operandplaatsing, prioriteit en associativiteit.
De
prefix
,infix
enpostfix
modificaties worden gebruikt om een aangepaste operatorverklaring te starten. Deprefix
enpostfix
modificatoren geven aan of de operator respectievelijk vóór of na de waarde moet staan waarop deze werkt. Dergelijke operatoren zijn urnary, zoals8
en3++
** , omdat ze slechts op één doel kunnen reageren. Deinfix
verklaart een binaire operator, die werkt op de twee waarden waartussen het ligt, zoals2+3
.Operators met een hogere prioriteit worden eerst berekend. De standaard operatorprioriteit is gewoon hoger dan
?
...:
(een waarde van 100 in Swift 2.x). De prioriteit van de standaard Swift operators kan worden gevonden hier .Associativiteit definieert de volgorde van bewerkingen tussen operatoren van dezelfde prioriteit. Linker associatieve operatoren worden van links naar rechts berekend (leesvolgorde, zoals de meeste operatoren), terwijl rechts associatieve operatoren van rechts naar links berekenen.
Beginnend met Swift 3.0 zou men de prioriteit en associativiteit in een prioriteitsgroep definiëren in plaats van de operator zelf, zodat meerdere operators gemakkelijk dezelfde prioriteit kunnen delen zonder naar de cryptische getallen te verwijzen. De lijst met standaard prioriteitsgroepen wordt hieronder weergegeven .
Operators retourneren waarden op basis van de berekeningscode. Deze code dient als een normale functie, met parameters die het soort ingangssignaal en het return
sleutelwoord vermelding van de berekende waarde die de gebruiker terugkeert.
Hier is de definitie van een eenvoudige exponentiële operator, omdat standaard Swift geen exponentiële operator heeft.
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
De infix
zegt dat de **
operator tussen twee waarden werkt, zoals 9**2
. Omdat de functie associativiteit heeft verlaten, wordt 3**3**2
berekend als (3**3)**2
. De prioriteit van 170
is hoger dan alle standaard Swift-bewerkingen, wat betekent dat 3+2**4
berekend wordt tot 19
, ondanks de linkse associativiteit van **
.
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
In plaats van de prioriteit en associativiteit expliciet op te geven, zouden we op Swift 3.0 de ingebouwde prioriteitsgroep BitwiseShiftPrecedence kunnen gebruiken die de juiste waarden geeft (hetzelfde als <<
, >>
).
**: De toename en afname zijn verouderd en worden verwijderd in Swift 3.
Overbelasting + voor woordenboeken
Aangezien er momenteel geen eenvoudige manier is om woordenboeken in Swift te combineren, kan het handig zijn om de operatoren +
en +=
te overbelasten om deze functionaliteit met behulp van generieke geneesmiddelen toe te voegen.
// 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
}
}
Vanaf Swift 3 moet inout
vóór het argumenttype worden geplaatst.
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
Voorbeeld gebruik:
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"]
Commutatieve operators
Laten we een aangepaste operator toevoegen om een CGSize te vermenigvuldigen
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
Nu werkt dit
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
Maar als we proberen de bewerking in omgekeerde volgorde uit te voeren, krijgen we een foutmelding
let sizeC = sizeB * 20 // ERROR
Maar het is eenvoudig genoeg om toe te voegen:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
Nu is de operator commutatief.
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
Bitwise Operators
Met snelle Bitwise-operatoren kunt u bewerkingen uitvoeren op de binaire vorm van getallen. U kunt een binaire letterlijke waarde opgeven door het getal vooraf te laten gaan door 0b
, dus 0b110
is bijvoorbeeld gelijk aan het binaire getal 110 (het decimale getal 6). Elke 1 of 0 is een beetje in het nummer.
Bitwise NOT ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
Hier wordt elk bit veranderd in het tegenovergestelde. Het nummer expliciet UInt8
zorgt ervoor dat het nummer positief is (zodat we niet met negatieven in het voorbeeld te maken hebben) en dat het slechts 8 bits is. Als 0b01101100
een grotere UInt was, zouden er voorloopnullen zijn die worden geconverteerd naar en en significant worden bij inversie:
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
Bitwise AND &
:
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
Hier is een gegeven bit 1 als en alleen als de binaire getallen aan beide zijden van de &
operator een 1 bevatten op die bitlocatie.
- 0 & 0 -> 0
- 0 & 1 -> 0
- 1 & 1 -> 1
Bitgewijs OF |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
Hier is een gegeven bit 1 als en alleen als het binaire getal aan ten minste één zijde van de |
operator bevatte een 1 op die bitlocatie.
- 0 | 0 -> 0
- 0 | 1 -> 1
- 1 | 1 -> 1
Bitwise XOR (exclusief OF) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
Hier is een gegeven bit 1 als en alleen als de bits in die positie van de twee operanden verschillend zijn.
- 0 ^ 0 -> 0
- 0 ^ 1 -> 1
- 1 ^ 1 -> 0
Voor alle binaire bewerkingen maakt de volgorde van de operanden geen verschil in het resultaat.
Overloopoperators
Overloop verwijst naar wat er gebeurt als een bewerking zou resulteren in een getal dat groter of kleiner is dan het toegewezen aantal bits voor dat nummer.
Vanwege de manier waarop binaire rekenkunde werkt, stroomt het nummer, nadat een getal te groot is geworden voor zijn bits, over naar het kleinst mogelijke getal (voor de bitgrootte) en gaat dan verder met tellen. Evenzo, wanneer een nummer te klein wordt, stroomt het naar het grootst mogelijke nummer (vanwege de bitgrootte) en blijft het aftellen vanaf daar.
Omdat dit gedrag niet vaak gewenst is en tot ernstige beveiligingsproblemen kan leiden, geven de rekenkundige operatoren Swift +
, -
en *
fouten wanneer een bewerking een overloop of onderloop zou veroorzaken. Gebruik in plaats daarvan &+
, &-
en &*
om overloop en onderloop expliciet toe te staan.
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
Voorrang van standaard Swift-operators
Operatoren die strakker gebonden zijn (hogere prioriteit) worden eerst vermeld.
operators | Voorrangsgroep (≥3.0) | Voorrang | associativiteit |
---|---|---|---|
. | ∞ | links | |
? , ! , ++ , -- , [] , () , {} | (Postfix) | ||
! , ~ , + , - , ++ , -- | (voorvoegsel) | ||
~> (snel ≤2.3) | 255 | links | |
<< , >> | BitwiseShiftPrecedence | 160 | geen |
* , / , % , & , &* | MultiplicationPrecedence | 150 | links |
+ , - , | , ^ , &+ , &- | AdditionPrecedence | 140 | links |
... , ..< | RangeFormationPrecedence | 135 | geen |
is , as , as? as! | CastingPrecedence | 132 | links |
?? | NilCoalescingPrecedence | 131 | Rechtsaf |
< , <= , > , >= , == != , === !== , ~= | ComparisonPrecedence | 130 | geen |
&& | LogicalConjunctionPrecedence | 120 | links |
|| | LogicalDisjunctionPrecedence | 110 | links |
DefaultPrecedence * | geen | ||
? ... : | TernaryPrecedence | 100 | Rechtsaf |
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= | AssignmentPrecedence | 90 | recht, opdracht |
-> | FunctionArrowPrecedence | Rechtsaf |
- De standaardvoorrangsgroep
DefaultPrecedence
is hoger danTernaryPrecedence
, maar is niet geordend bij de rest van de operatoren. Anders dan deze groep, zijn de rest van de prioriteiten lineair.
- Deze tabel is ook te vinden in de API-referentie van Apple
- De feitelijke definitie van de prioriteitsgroepen is te vinden in de broncode op GitHub