Προεπιλεγμένες τιμές παραμέτρων μπορούν να δοθούν για οποιαδήποτε από τις παραμέτρους μιας συνάρτησης, αναθέτοντας μια τιμή στην παράμετρο στη λίστα παραμέτρων, αμέσως μετά την υπόδειξη τύπου της παραμέτρου. Όταν οριστεί μια προεπιλεγμένη τιμή παραμέτρου, όποιος καλεί τη συνάρτηση μπορεί να παραλείψει αυτή την παράμετρο και θα χρησιμοποιηθεί η προεπιλεγμένη τιμή.
func greeting(name: String = "guest", duration: Int = 2) -> String {
"Welcome, \(name). Enjoy your \(duration) night stay."
}
greeting(name: "Bobo", duration: 7)
// Returns "Welcome, Bobo. Enjoy your 7 night stay."
greeting(duration: 3)
// Returns "Welcome, guest. Enjoy your 3 night stay."
greeting(name: "Wynona")
// Returns "Welcome, Wynona. Enjoy your 2 night stay."
greeting()
// Returns "Welcome, guest. Enjoy your 2 night stay."
Οι παράμετροι μεταβλητού πλήθους επιτρέπουν σε μια συνάρτηση να δέχεται μηδέν ή περισσότερες τιμές ενός συγκεκριμένου τύπου για μία μόνο παράμετρο.
Ορίζεις μια παράμετρο μεταβλητού πλήθους προσθέτοντας τρεις τελείες (...) στο τέλος της υπόδειξης τύπου της παραμέτρου.
Μέσα στο σώμα της συνάρτησης, η Swift κάνει αυτές τις τιμές διαθέσιμες ως πίνακα του συγκεκριμένου τύπου:
import Foundation
func geometricMean(_ numbers: Double...) -> Double {
var total = 1.0
for number in numbers {
total *= number
}
return pow(total, 1.0 / Double(numbers.count))
}
let result = geometricMean(1, 2, 3, 4, 5)
// result is 2.605171084697352
Αν μια συνάρτηση περιλαμβάνει επιπλέον παραμέτρους μετά από μια παράμετρο μεταβλητού πλήθους, η πρώτη παράμετρος μετά την παράμετρο μεταβλητού πλήθους πρέπει να έχει ρητή ετικέτα ορίσματος, ώστε η Swift να ξέρει πού τελειώνει η λίστα ορισμάτων μεταβλητού πλήθους.
Μέσα στο σώμα μιας συνάρτησης, οι παράμετροι αντιμετωπίζονται ως σταθερές, όχι ως μεταβλητές. Η προσπάθεια να τροποποιήσεις την τιμή μιας παραμέτρου θα πετάξει ένα σφάλμα κατά τη μεταγλώττιση. Αν μια συνάρτηση θέλει να τροποποιήσει την τιμή μιας παραμέτρου, πρέπει να χρησιμοποιήσει μια παράμετρο in-out, ώστε να δηλώσει ρητά αυτή τη μεταβλητότητα.
Για να χρησιμοποιήσεις παραμέτρους in-out, πρέπει να ισχύουν τρία πράγματα:
inout ανάμεσα στο : και στο όνομα του τύπου στην υπόδειξη τύπου της παραμέτρου.& στην κλήση της συνάρτησης, σημαδεύοντάς την ρητά ως τροποποιήσιμη.Όταν γίνουν όλα αυτά, η συνάρτηση δημιουργεί ένα εσωτερικό αντίγραφο της παραμέτρου in-out, το τροποποιεί όπως ορίζει το σώμα της συνάρτησης και έπειτα αντιγράφει την τροποποιημένη τιμή πίσω στη μεταβλητή που είχε περαστεί, όταν η συνάρτηση επιστρέψει.
func updateVersion(_ record: inout (version: Int, title: String)) {
record.version += 1
}
var dbRecord = (version: 2, title: "Exercism")
updateVersion(&dbRecord)
// dbRecord is now (3, "Exercism")
Υπάρχουν μερικοί επιπλέον κανόνες που καλό είναι να γνωρίζεις σχετικά με τις παραμέτρους in-out.
1. Μέσα σε μια συνάρτηση με παραμέτρους in-out, δεν επιτρέπεται να αναφερθείς στη μεταβλητή που περάστηκε ως η παράμετρος in-out.
2. Η ίδια μεταβλητή δεν μπορεί να περαστεί ως πολλαπλές παράμετροι in-out στην ίδια συνάρτηση.
Για παράδειγμα, το `inoutFunc(&mutVar, &mutVar)` πετάει ένα σφάλμα μεταγλώττισης.
Στη Swift, μπορείς να ορίσεις συναρτήσεις μέσα σε άλλες συναρτήσεις. Αυτές ονομάζονται εμφωλευμένες συναρτήσεις.
Οι εμφωλευμένες συναρτήσεις χρησιμοποιούνται συχνά ως ιδιωτικές βοηθητικές συναρτήσεις που εκτελούν συγκεκριμένες εργασίες για τη συνάρτηση που τις περιέχει, χωρίς να επιβαρύνουν το εξωτερικό πεδίο:
func makeNumber(_ number: Int) -> Int {
func double(_ x: Int) -> Int {
x * 2
}
func increment(_ x: Int) -> Int {
x + 1
}
return number.isMultiple(of: 2) ? increment(double(number)) : double(number)
}
print(makeNumber(3)) // Prints 6
print(makeNumber(4)) // Prints 9
Οι εμφωλευμένες συναρτήσεις συμπεριφέρονται όπως οι κανονικές συναρτήσεις, αλλά η ορατότητά τους περιορίζεται στο σώμα της συνάρτησης που τις περιέχει.
Σε αυτή την άσκηση θα γράψεις λίγο ακόμα κώδικα για να σε βοηθήσει να μαγειρέψεις τα υπέροχα λαζάνια σου από το αγαπημένο σου βιβλίο μαγειρικής.
Έχεις πέντε εργασίες, όλες σχετικές με τον χρόνο που περνάς μαγειρεύοντας τα λαζάνια.
Θέλεις να γράψεις μια βελτιωμένη συνάρτηση remainingMinutesInOven που παίρνει ως παράμετρο τον αριθμό των λεπτών που τα λαζάνια βρίσκονται στον φούρνο και επιστρέφει πόσα λεπτά πρέπει ακόμα να μείνουν τα λαζάνια στον φούρνο, με βάση τον αναμενόμενο χρόνο ψησίματος σε λεπτά από την προηγούμενη εργασία.
Προηγουμένως, είχες βασιστεί σε μια σταθερή τιμή, το expectedMinutesInOven, που ερχόταν από έξω από τη συνάρτηση remainingMinutesInOven.
Αυτό ήταν και λίγο πιο φορτωμένο απ' όσο σου άρεσε και όχι αρκετά ευέλικτο, αφού δε σου επιτρέπει να αλλάξεις τον αναμενόμενο χρόνο στον φούρνο.
Για να τακτοποιήσεις τα πράγματα, όρισε τη συνάρτηση remainingMinutesInOven που παίρνει ως παράμετρο τον αριθμό των λεπτών που τα λαζάνια βρίσκονται στον φούρνο, καθώς και μια παράμετρο expectedMinutesInOven που έχει προεπιλεγμένη τιμή 40.
Η συνάρτησή σου πρέπει να επιστρέφει πόσα λεπτά πρέπει ακόμα να μείνουν τα λαζάνια στον φούρνο, με βάση τον αναμενόμενο χρόνο ψησίματος σε λεπτά από την προηγούμενη εργασία.
remainingMinutesInOven(elapsedMinutes: 30)
// Returns 10
remainingMinutesInOven(elapsedMinutes: 30, expectedMinutesInOven: 75)
// Returns 45
Είχες προηγουμένως γράψει μια συνάρτηση preparationTimeInMinutes που παίρνει ως παράμετρο τον αριθμό των στρώσεων που πρόσθεσες στα λαζάνια και επιστρέφει πόσα λεπτά πέρασες προετοιμάζοντας τα λαζάνια, υποθέτοντας ότι κάθε στρώση σου παίρνει 2 λεπτά για να προετοιμαστεί.
Ωστόσο, δεν είσαι ιδιαίτερα ευχαριστημένος με αυτή τη συνάρτηση, αφού πρέπει να μετρήσεις μόνος σου τον αριθμό των στρώσεων στα λαζάνια σου πριν καλέσεις αυτή τη συνάρτηση, και ποιος έχει χρόνο για όλα αυτά;
Για να κάνεις τα πράγματα πιο εύκολα για τον εαυτό σου, γράψε μια συνάρτηση, preparationTimeInMinutes, που παίρνει μια variadic παράμετρο String με το όνομα layers, όπου παραθέτεις τις διαφορετικές στρώσεις των λαζανιών σου.
Η συνάρτηση θα μετρήσει τότε τον αριθμό των στρώσεων στα λαζάνια σου και θα επιστρέψει τον χρόνο προετοιμασίας που απαιτείται.
preparationTimeInMinutes(layers: "sauce", "noodles")
// Returns 4
preparationTimeInMinutes(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns 24
Πριν αρχίσεις να συναρμολογείς τα λαζάνια σου, θέλεις να βεβαιωθείς ότι έχεις αρκετή σάλτσα και νουντλς για να φτιάξεις τα λαζάνια των ονείρων σου. Για κάθε στρώση νουντλς στα λαζάνια σου, θα χρειαστείς 3 νουντλς. Για κάθε στρώση σάλτσας στα λαζάνια σου, θα χρειαστείς 0,2 λίτρα σάλτσας.
Όρισε τη συνάρτηση quantities που παίρνει μια variadic παράμετρο String με το όνομα layers, όπου παραθέτεις τις διαφορετικές στρώσεις των λαζανιών σου.
Η συνάρτηση θα προσδιορίσει τότε την ποσότητα νουντλς και σάλτσας που χρειάζεται για το γεύμα σου. Το αποτέλεσμα πρέπει να επιστρέφεται σε μια πλειάδα τύπου (noodles: Int, sauce: Double).
quantities(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns (noodles: 9, sauce: 0.8)
quantities(layers: "sauce", "noodles", "sauce", "noodles", "meat", "noodles", "mozzarella")
// Returns (noodles: 9, sauce: 0.4)
Δυστυχώς, ο όγκος της σάλτσας που έχεις πρόχειρη αναγράφεται σε ουγγιές υγρού αντί για λίτρα.
Για να σε βοηθήσει να καταλάβεις αν έχεις αρκετή σάλτσα πρόχειρη, γράψε μια συνάρτηση, toOz, που παίρνει μια in-out παράμετρο πλειάδας, (noodles: Int, sauce: Double), και μετατρέπει την ποσότητα της σάλτσας σε ουγγιές υγρού.
Σημείωσε ότι υπάρχουν 33,814 ουγγιές υγρού ανά λίτρο.
var amount = (noodles: 9, sauce: 0.8)
toOz(&amount)
amount
// Returns (noodles: 9, sauce: 27.0512)
Τέλος, θέλεις να μάθεις τι είδος κρασιού να σερβίρεις με τα λαζάνια σου.
Έχεις ακούσει ότι πρέπει να σερβίρεις λευκό κρασί αν τα λαζάνια έχουν περισσότερη μοτσαρέλα, ρικότα και μπεσαμέλ απ' ό,τι κρέας και σάλτσα, και κόκκινο κρασί σε αντίθετη περίπτωση.
Γράψε μια συνάρτηση redWine που παίρνει μια variadic παράμετρο String με το όνομα layers, όπου παραθέτεις τις διαφορετικές στρώσεις των λαζανιών σου.
Η συνάρτηση θα χρησιμοποιήσει πέντε εμφωλευμένες συναρτήσεις για να προσδιορίσει τον αριθμό των στρώσεων μοτσαρέλας, ρικότας, μπεσαμέλ, σάλτσας και κρέατος στα λαζάνια, και θα συγκρίνει τους αριθμούς των στρώσεων για να προσδιορίσει αν πρέπει να σερβιριστεί κόκκινο κρασί, επιστρέφοντας true αν ναι και false αν όχι.
redWine(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns true
redWine(layers: "sauce", "noodles", "béchamel", "meat", "mozzarella", "noodles", "ricotta", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns false
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Swift με 35 έννοιες116 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.