A closure a Swiftben egy önálló kódblokk: paramétereket adhatsz át neki, amivel elindítod a számítását, és értéket ad vissza. A closure emellett értékeket is rögzít a környezetéből, és felhasználja őket a számításaiban. Mivel önmagában áll, a programban ugyanúgy továbbadhatod, mint bármely más értéket, vagy hozzárendelheted konstansokhoz és változókhoz.
A closure nagyon hasonlíthat a Swift-függvényekre, és valóban hasonlít is, méghozzá jó okkal. A Swift-függvény valójában a closure egy speciális esete: neki kötelező a neve, és egy kicsit más szintaxissal definiáljuk.
Bár a Swift-függvény technikailag closure, amikor az emberek „closures”-ról beszélnek a Swiftben, valójában closure expressionre gondolnak.
A closure expression a következőképpen íródik le: egy paraméterlista, majd a visszatérési típus, majd az in kulcsszó és a closure törzse, mindez egy pár kapcsos zárójelben:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}
Ez egy (Double, Double) -> Double típusú closure expressiont definiál, és ugyanúgy végrehajtható, mint egy ilyen típusú függvény, ha a megfelelő típusú paraméterekre alkalmazod:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}(10.0, 15.0)
// returns 12.5
Mivel nem túl kényelmes minden alkalommal kiírni a teljes closure expressiont, amikor végre akarod hajtani, a closure hozzárendelhető egy névhez, akárcsak a Swift bármely más értéke. Ezután úgy hívhatod meg, hogy a nevet a paraméterekre alkalmazod:
let mean = { (a: Double, b: Double) -> Double in
(a + b) / 2.0
}
mean(13.0, 100.0)
// returns 56.5
Ahogy fentebb láttuk, a closure a hagyományos függvényekhez hasonlóan elhagyhatja a return kulcsszót, ha a törzse egyetlen kifejezésből áll.
Leggyakrabban a closure-t magasabb rendű függvényekkel együtt használjuk: vagy paraméterként adjuk át nekik, vagy visszatérési értékként kapjuk vissza:
[11, 75, 3, 99, 53].contains(where: { (x: Int) -> Bool in x > 100 })
// returns false
["apple", "ball", "carrot"].sorted(by: { (s1: String, s2: String) -> Bool in s1.count < s2.count })
// returns ["ball", "apple", "carrot"]
func makeAdder(base: Int) -> (Int) -> Int {
{ (x: Int) -> Int in base + x }
}
Ismét üdv, Double-Null0111 ügynök!
Az UMBRA erői megint mozgolódnak, és rajtad múlik, hogy meghiúsítsd a legújabb tervüket. A hírszerző részlegünk arról értesített minket, hogy a Minionok bűzbombát készülnek elsütni a kormányzó bálján.
Mivel a minionok olyan ügyetlenek, gyakran véletlenül aktiválják a bűzbombákat a laborjaikban és az irodáikban. És mivel folyton elfelejtik, hogyan kell hatástalanítani a bűzbombáikat, létrehoztak egy rendszert, amely legyártja a hatástalanítási utasításokat. Ezek a bomba azonosítószáma alapján megadják, milyen sorrendben kell elvágni a vezetékeket.
A feladatod, hogy megírd azt a kódot, amellyel hatástalanítani tudod a bálon a bűzbombát, mielőtt elsül.
Minden bűzbombán három különböző színű vezeték van.
Írj egy closure-t, amely átvesz egy (String, String, String) tuple-t, és visszaadja a tuple-t úgy, hogy az első két elem sorrendje felcserélődik.
Rendeld ezt a closure-t a flip névhez.
Fontos megjegyezni, hogy a típusnak ChangeClosure-nek (vagy egy sendable típusnak) kell lennie; a típusdefiníció a stub fájlban található.
Ellenkező esetben a kód nem fordul le.
flip(("red", "yellow", "blue"))
// Returns ("yellow", "red", "blue")
Írj egy closure-t, amely átvesz egy (String, String, String) tuple-t, és visszaadja a tuple-t úgy, hogy a vezetékek sorrendje balra elforgatva.
Rendeld ezt a closure-t a rotate névhez.
Fontos megjegyezni, hogy a típusnak ChangeClosure-nek (vagy egy sendable típusnak) kell lennie; a típusdefiníció a stub fájlban található.
rotate(("red", "yellow", "blue"))
// Returns ("yellow", "blue", "red")
Ahhoz, hogy kitaláld, milyen sorrendben kell elvágni a bűzbomba vezetékeit, meg kell valósítanod egy függvényt, amely a bűzbomba azonosítószáma alapján legyártja a megfelelő keverőfüggvényt.
Valósítsd meg a függvényt:
makeShuffle(
flipper: @escaping ((String, String, String)) -> (String, String, String),
rotator: @escaping ((String, String, String)) -> (String, String, String)
) -> ([UInt8], (String, String, String)) -> (String, String, String)
amely bemenetként átvesz egy closure-t, amely megcserél két vezetéket, és egy closure-t, amely elforgatja a három vezetéket, majd visszaad egy closure-t. Ez a visszaadott closure átveszi a bűzbomba azonosítószámát és a három vezeték sorrendjét, majd kiszámítja, milyen sorrendben kell elvágni a vezetékeket. Az azonosítószám nyolc bitből áll, és minden bit eldönti, hogy meg kell-e cserélni vagy el kell-e forgatni a vezetékeket.
Az azonosítószám minden bitjére, a jobb szélső bittel kezdve, a flipper closure-t alkalmazod a vezetékek tuple-jére, ha a bit 0, és a rotator closure-t alkalmazod, ha a bit 1; így megkapod a vezetékek új állapotát.
Miután mind a nyolc bitre alkalmaztad a hozzá tartozó closure-t, a vezetékek végső állapota adja meg azt a sorrendet, amelyben el kell vágni őket.
let shuffler = makeShuffle(flipper: flip, rotator: rotate)
// Returns ([UInt8], (String, String, String)) -> (String, String, String)
shuffler([1, 0, 0, 1, 1, 0, 1, 1], ("red", "yellow", "blue"))
// Returns ("red", "blue", "yellow")
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Swift nyelvet 35 fogalom116 feladat segítségével, valódi emberi mentorálással, mindez ingyen.