Οι κλειστές στη Swift είναι αυτοτελή μπλοκ κώδικα στα οποία μπορούν να περαστούν παράμετροι για να ενεργοποιήσουν τον υπολογισμό τους και να επιστρέψουν τιμές. Οι κλειστές επίσης συλλαμβάνουν τιμές από το περιβάλλον τους και τις χρησιμοποιούν στους υπολογισμούς τους. Καθώς είναι αυτοτελείς, μπορούν να μεταβιβάζονται σε ένα πρόγραμμα όπως άλλες τιμές ή να ανατίθενται σε σταθερές και μεταβλητές.
Οι κλειστές μπορεί να μοιάζουν πολύ με τις συναρτήσεις της Swift· και πράγματι μοιάζουν, για καλό λόγο. Οι συναρτήσεις στη Swift είναι ειδικές περιπτώσεις κλειστών που απαιτείται να έχουν όνομα και ορίζονται χρησιμοποιώντας μια ελαφρώς διαφορετική σύνταξη.
Ενώ οι συναρτήσεις στη Swift είναι τεχνικά κλειστές, όταν οι άνθρωποι αναφέρονται σε "κλειστές" στη Swift, εννοούν τις κλειστές εκφράσεις.
Οι κλειστές εκφράσεις γράφονται ως μια λίστα παραμέτρων ακολουθούμενη από έναν τύπο επιστροφής και τη λέξη-κλειδί in ακολουθούμενη από το σώμα της κλειστής, όλα μέσα σε ένα ζεύγος αγκίστρων:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}
Αυτό ορίζει μια κλειστή έκφραση τύπου (Double, Double) -> Double, και μπορεί να εκτελεστεί με παρόμοιο τρόπο όπως μια συνάρτηση αυτού του τύπου, εφαρμόζοντάς την σε παραμέτρους του κατάλληλου τύπου:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}(10.0, 15.0)
// returns 12.5
Καθώς δεν είναι πολύ βολικό να γράφεις ολόκληρη την κλειστή έκφραση κάθε φορά που θέλεις να την εκτελέσεις, οι κλειστές μπορούν να ανατεθούν σε ονόματα, όπως οποιαδήποτε άλλη τιμή στη Swift. Στη συνέχεια μπορούν να κληθούν εφαρμόζοντας το όνομα στις παραμέτρους:
let mean = { (a: Double, b: Double) -> Double in
(a + b) / 2.0
}
mean(13.0, 100.0)
// returns 56.5
Όπως φαίνεται παραπάνω, οι κλειστές, όπως οι κανονικές συναρτήσεις, μπορούν να παραλείψουν τη λέξη-κλειδί return εάν το σώμα της κλειστής είναι μία μόνο έκφραση.
Τις περισσότερες φορές, οι κλειστές χρησιμοποιούνται με συναρτήσεις υψηλότερης τάξης, είτε περνώντας τις ως παραμέτρους είτε επιστρέφοντάς τις ως αποτελέσματα:
[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 }
}
Γεια σου και πάλι, Πράκτορα Double-Null0111.
Οι δυνάμεις της UMBRA ξαναχτυπούν, και εξαρτάται από εσένα να ματαιώσεις το τελευταίο τους σχέδιο. Η υπηρεσία πληροφοριών μας μάς ενημερώνει ότι αυτά τα Minions σχεδιάζουν να πυροδοτήσουν μια βομβίδα βρώμας στον χορό του Κυβερνήτη.
Επειδή τα Minions είναι τόσο αδέξια, συχνά οπλίζουν κατά λάθος τις βομβίδες βρώμας στα εργαστήρια και τα γραφεία τους. Και επειδή συνεχώς ξεχνούν πώς να απενεργοποιήσουν τις βομβίδες βρώμας τους, έχουν υλοποιήσει ένα σύστημα που δημιουργεί τις οδηγίες απενεργοποίησης, οι οποίες αναφέρουν τη σειρά με την οποία πρέπει να κοπούν τα καλώδια με βάση τον αριθμό ID της βομβίδας.
Η δουλειά σου είναι να γράψεις τον κώδικα που θα σου επιτρέψει να απενεργοποιήσεις τη βομβίδα βρώμας στον χορό πριν εκραγεί.
Κάθε βομβίδα βρώμας έχει τρία καλώδια με διαφορετικά χρώματα.
Γράψε ένα closure που παίρνει μια πλειάδα (String, String, String) και επιστρέφει την πλειάδα με αντεστραμμένη τη σειρά των δύο πρώτων στοιχείων.
Ανάθεσε αυτό το closure στο όνομα flip.
Είναι σημαντικό να σημειώσεις ότι ο τύπος πρέπει να είναι ο ChangeClosure (ή κάποιος sendable τύπος), ο ορισμός του τύπου δίνεται στο αρχείο stub.
Διαφορετικά, ο κώδικας δεν θα μεταγλωττιστεί.
flip(("red", "yellow", "blue"))
// Returns ("yellow", "red", "blue")
Γράψε ένα closure που παίρνει μια πλειάδα (String, String, String) και επιστρέφει την πλειάδα με τη σειρά των καλωδίων περιστραμμένη προς τα αριστερά.
Ανάθεσε αυτό το closure στο όνομα rotate.
Είναι σημαντικό να σημειώσεις ότι ο τύπος πρέπει να είναι ο ChangeClosure (ή κάποιος sendable τύπος), ο ορισμός του τύπου δίνεται στο αρχείο stub.
rotate(("red", "yellow", "blue"))
// Returns ("yellow", "blue", "red")
Για να βρεις τη σειρά με την οποία πρέπει να κόψεις τα καλώδια της βομβίδας βρώμας, θα χρειαστεί να υλοποιήσεις μια συνάρτηση που παράγει τη σωστή συνάρτηση ανακατέματος με βάση τον αριθμό ID της βομβίδας βρώμας.
Υλοποίησε τη συνάρτηση:
makeShuffle(
flipper: @escaping ((String, String, String)) -> (String, String, String),
rotator: @escaping ((String, String, String)) -> (String, String, String)
) -> ([UInt8], (String, String, String)) -> (String, String, String)
η οποία παίρνει ως είσοδο ένα closure που αντιστρέφει δύο καλώδια και ένα closure που περιστρέφει τα τρία καλώδια, και επιστρέφει ένα closure. Αυτό το closure που επιστρέφεται παίρνει τον αριθμό ID της βομβίδας βρώμας και τη σειρά των τριών καλωδίων, και έπειτα υπολογίζει τη σειρά με την οποία πρέπει να κοπούν τα καλώδια. Ο αριθμός ID αποτελείται από οκτώ bits, και κάθε bit καθορίζει αν θα αντιστραφούν ή θα περιστραφούν τα καλώδια.
Για κάθε bit του αριθμού ID, ξεκινώντας από το δεξιότερο bit, θα εφαρμόζεις το closure flipper στην πλειάδα των καλωδίων αν το bit είναι 0, και θα εφαρμόζεις το closure rotator αν είναι 1, δίνοντας τη νέα κατάσταση των καλωδίων.
Αφού εφαρμοστούν τα κατάλληλα closures και για τα οκτώ bits του ID, η τελική κατάσταση των καλωδίων είναι η σειρά με την οποία πρέπει να κοπούν.
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")
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Swift με 35 έννοιες116 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.