Swift Language
Avancerade operatörer
Sök…
Anpassade operatörer
Swift stöder skapandet av anpassade operatörer. Nya operatörer deklareras på global nivå med hjälp av operator
nyckelord.
Operatörens struktur definieras av tre delar: operandplacering, företräde och associativitet.
prefix
,infix
ochpostfix
används för att starta en anpassad operatörsdeklaration.postfix
prefix
ochpostfix
anger huruvida operatören måste vara respektive före eller efter det värde som den verkar på. Sådana operatörer är urnary, som8
och3++
** , eftersom de bara kan agera på ett mål.infix
deklarerar en binär operatör som verkar på de två värdena den är mellan, till exempel2+3
.Operatörer med högre prioritet beräknas först. Standardoperatörens företräde är bara högre än
?
...:
(ett värde på 100 i Swift 2.x). Företräde för vanliga Swift-operatörer kan hittas här .Associativity definierar ordningen på operationer mellan operatörer med samma prioritet. Vänsterassosierande operatörer beräknas från vänster till höger (läsordning, som de flesta operatörer), medan högerassocierande operatörer beräknar från höger till vänster.
Från och med Swift 3.0 skulle man definiera företräde och associativitet i en prioritetsgrupp istället för själva operatören, så att flera operatörer enkelt kan dela samma företräde utan att hänvisa till de kryptiska siffrorna. Listan över standardprioritetsgrupper visas nedan .
Operatörer returnerar värden baserade på beräkningskoden. Denna kod fungerar som en normal funktion, med parametrar som anger vilken typ av ingång och return
nyckelordet specificerar det beräknade värdet som operatören avkastning.
Här är definitionen av en enkel exponentiell operatör, eftersom standard Swift inte har en exponentiell operatör.
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
infix
säger att **
operatören arbetar mellan två värden, till exempel 9**2
. Eftersom funktionen har lämnat associativitet beräknas 3**3**2
som (3**3)**2
. Förekomsten av 170
är högre än alla vanliga Swift-operationer, vilket betyder att 3+2**4
beräknar till 19
, trots den vänstra associativiteten **
.
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
Istället för att specificera precedensen och associativiteten uttryckligen, på Swift 3.0 kan vi använda den inbyggda företrädesgruppen BitwiseShiftPrecedence som ger rätt värden (samma som <<
, >>
).
**: Ökning och minskning avskrivs och tas bort i Swift 3.
Överbelastning + för ordböcker
Eftersom det för närvarande inte finns något enkelt sätt att kombinera ordböcker i Swift, kan det vara användbart att överbelasta operatörerna +
och +=
för att lägga till denna funktionalitet med hjälp av generik .
// 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
}
}
Från och med Swift 3 bör inout
placeras före argumenttypen.
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
Exempel på användning:
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"]
Kommutativa operatörer
Låt oss lägga till en anpassad operatör för att multiplicera en CGS-storlek
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
Nu fungerar det
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
Men om vi försöker göra operationen omvänd, får vi ett fel
let sizeC = sizeB * 20 // ERROR
Men det är enkelt att lägga till:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
Nu är operatören kommutativ.
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
Bitvisa operatörer
Snabba bitvisa operatörer låter dig utföra operationer i binär form av siffror. Du kan ange en binär bokstavskod genom att prefixera siffran med 0b
, så till exempel 0b110
motsvarar det binära numret 110 (decimaltalet 6). Varje 1 eller 0 är lite i siffran.
Bitvis INTE ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
Här förändras varje bit till motsatsen. Att ange antalet som uttryckligen UInt8
säkerställer att antalet är positivt (så att vi inte behöver ta itu med negativa i exemplet) och att det bara är 8 bitar. Om 0b01101100
var ett större användargränssnitt, skulle det finnas ledande 0: er som skulle omvandlas till 1s och bli betydande vid inversion:
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
Bitvis OCH &
:
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
Här kommer en given bit att vara 1 om och bara om de binära siffrorna på båda sidor om &
operatören innehöll en 1 på den bitpositionen.
- 0 & 0 -> 0
- 0 & 1 -> 0
- 1 & 1 -> 1
Bitvis ELLER |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
Här kommer en given bit att vara 1 om och bara om det binära talet på minst en sida av |
operatören innehöll en 1 på den bitplatsen.
- 0 | 0 -> 0
- 0 | 1 -> 1
- 1 | 1 -> 1
Bitvis XOR (exklusiv ELLER) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
Här kommer en given bit att vara 1 om och bara om bitarna i den positionen för de två operandema är olika.
- 0 ^ 0 -> 0
- 0 ^ 1 -> 1
- 1 ^ 1 -> 0
För alla binära operationer gör operandens ordning ingen skillnad på resultatet.
Överflödesoperatörer
Överflöde hänvisar till vad som händer när en operation skulle resultera i ett nummer som är antingen större eller mindre än det angivna antalet bitar för det numret kan innehålla.
På grund av hur binär aritmetik fungerar, efter att ett nummer blir för stort för sina bitar, flyter antalet ner till minsta möjliga antal (för bitstorleken) och fortsätter sedan att räkna upp därifrån. På samma sätt, när ett nummer blir för litet, flödar det upp till det största möjliga antalet (för sin bitstorlek) och fortsätter att räkna ner därifrån.
Eftersom detta beteende inte ofta önskas och kan leda till allvarliga säkerhetsproblem, kommer de snabba aritmetiska operatörerna +
, -
och *
att kasta fel när en operation skulle orsaka ett överflöde eller underflöde. För att uttryckligen tillåta överflöde och underflöde, använd &+
, &-
och &*
istället.
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
Företräde för vanliga Swift-operatörer
Operatörer som bundit hårdare (högre prioritet) listas först.
operatörer | Företrädesgrupp (≥3,0) | Företräde | associativitet |
---|---|---|---|
. | ∞ | vänster | |
? , ! , ++ , -- , [] , () , {} | (Postfix) | ||
! , ~ , + , - , ++ , -- | (prefix) | ||
~> (snabb ≤2,3) | 255 | vänster | |
<< , >> | BitwiseShiftPrecedence | 160 | ingen |
* , / , % , & , &* | MultiplicationPrecedence | 150 | vänster |
+ , - , | , ^ , &+ , &- | AdditionPrecedence | 140 | vänster |
... , ..< | RangeFormationPrecedence | 135 | ingen |
is , as , as? , as! | CastingPrecedence | 132 | vänster |
?? | NilCoalescingPrecedence | 131 | rätt |
< , <= , > , >= , == === != , === !== , ~= | ComparisonPrecedence | 130 | ingen |
&& | LogicalConjunctionPrecedence | 120 | vänster |
|| | LogicalDisjunctionPrecedence | 110 | vänster |
DefaultPrecedence * | ingen | ||
? ... : | TernaryPrecedence | 100 | rätt |
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= | AssignmentPrecedence | 90 | rätt, uppdrag |
-> | FunctionArrowPrecedence | rätt |
-
DefaultPrecedence
företrädesgruppen är högre änTernaryPrecedence
, men är inte ordnad med resten av operatörerna. Utöver denna grupp är resten av föregångarna linjära.
- Tabellen finns också på Apples API-referens
- Den faktiska definitionen av företrädesgrupper kan hittas i källkoden på GitHub