Kurzusok
/
Swift
Swift
/
Feladatok
/
Double-Null0111: A closure-ök örökké élnek
Double-Null0111: A closure-ök örökké élnek

Double-Null0111: A closure-ök örökké élnek

Tanulófeladat

Bevezetés

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

Utasítások

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.

1. Írj closure-t, amely megcserél két vezetéket

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")

2. Írj closure-t, amely elforgatja a vezetékeket

Í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")

3. Készíts vezetékkeverő generátort

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")
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
Swift Exercism

Készen állsz elkezdeni a(z) Double-Null0111: A closure-ök örökké élnek feladatot?

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.