I valori predefiniti dei parametri possono essere assegnati a qualsiasi parametro di una funzione assegnando un valore al parametro nella lista dei parametri, subito dopo l'annotazione di tipo del parametro. Quando un parametro ha un valore predefinito, chi chiama la funzione può omettere quel parametro e al suo posto verrà usato il valore predefinito.
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."
I parametri variadici permettono a una funzione di accettare zero o più valori di un tipo specificato per un singolo parametro.
Si definisce un parametro variadico aggiungendo tre punti (...) all'annotazione di tipo del parametro.
All'interno del corpo della funzione, Swift rende questi valori disponibili come un array del tipo specificato:
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
Se una funzione include altri parametri dopo un parametro variadico, il primo parametro che segue il parametro variadico deve avere un'etichetta di argomento esplicita, così Swift sa dove finisce la lista degli argomenti variadici.
All'interno del corpo di una funzione, i parametri sono trattati come costanti, non come variabili; se provi a modificarne il valore, ottieni un errore in fase di compilazione. Se una funzione vuole modificare il valore di un parametro, deve usare un parametro in-out per rendere esplicita questa mutabilità.
Per usare i parametri in-out, chi programma deve fare attenzione a tre cose:
inout tra i : e il nome del tipo nell'annotazione di tipo del parametro.& nella chiamata alla funzione, contrassegnandola esplicitamente come modificabile.Quando tutto questo è rispettato, la funzione crea una copia interna del parametro in-out, la modifica come indicato nel corpo della funzione e poi, quando la funzione restituisce, copia il valore modificato nella variabile che era stata passata.
func updateVersion(_ record: inout (version: Int, title: String)) {
record.version += 1
}
var dbRecord = (version: 2, title: "Exercism")
updateVersion(&dbRecord)
// dbRecord is now (3, "Exercism")
Ci sono un paio di regole aggiuntive da tenere presenti riguardo ai parametri in-out.
1 All'interno di una funzione con parametri in-out, non puoi fare riferimento alla variabile passata come parametro in-out.
2. La stessa variabile non può essere passata come più parametri in-out nella stessa funzione.
Per esempio, `inoutFunc(&mutVar, &mutVar)` genera un errore del compilatore.
In Swift, puoi definire funzioni all'interno di altre funzioni. Queste sono note come funzioni annidate.
Le funzioni annidate si usano comunemente come funzioni ausiliarie private, che svolgono compiti specifici per la funzione che le contiene senza ingombrare lo scope esterno:
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
Le funzioni annidate si comportano come le funzioni normali, ma la loro visibilità è limitata al corpo della funzione che le contiene.
In questo esercizio scriverai altro codice per aiutarti a cucinare la tua fantastica lasagna dal tuo libro di cucina preferito.
Hai cinque attività, tutte legate al tempo di cottura della lasagna.
Vuoi scrivere una versione migliorata della funzione remainingMinutesInOven, che prende come parametro il numero di minuti trascorsi da quando la lasagna è in forno e restituisce quanti minuti deve ancora restare in forno, in base al tempo previsto in forno in minuti indicato nell'attività precedente.
In precedenza ti affidavi a un valore costante, expectedMinutesInOven, che veniva da fuori la funzione remainingMinutesInOven.
Era un po' troppo disordinato per i tuoi gusti e non abbastanza flessibile, perché non ti permetteva di cambiare il tempo previsto in forno.
Per fare ordine, definisci la funzione remainingMinutesInOven che prende come parametro il numero di minuti trascorsi da quando la lasagna è in forno, oltre a un parametro expectedMinutesInOven con un valore predefinito di 40.
La funzione deve restituire quanti minuti la lasagna deve ancora restare in forno, in base al tempo previsto in forno in minuti dell'attività precedente.
remainingMinutesInOven(elapsedMinutes: 30)
// Returns 10
remainingMinutesInOven(elapsedMinutes: 30, expectedMinutesInOven: 75)
// Returns 45
In precedenza avevi scritto una funzione preparationTimeInMinutes che prende come parametro il numero di strati che hai aggiunto alla lasagna e restituisce quanti minuti hai impiegato a prepararla, dando per scontato che ogni strato richieda 2 minuti.
Però questa funzione non ti soddisfa granché, perché devi contare da solo il numero di strati della lasagna prima di poterla chiamare, e chi ha tempo per tutto questo?
Per semplificarti le cose, scrivi una funzione preparationTimeInMinutes che prende un parametro variadico di tipo String, layers, in cui elenchi i diversi strati della lasagna.
La funzione conterà poi il numero di strati della lasagna e restituirà il tempo di preparazione necessario.
preparationTimeInMinutes(layers: "sauce", "noodles")
// Returns 4
preparationTimeInMinutes(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns 24
Prima di iniziare a comporre la lasagna, vuoi assicurarti di avere abbastanza salsa e noodles per costruire la lasagna dei tuoi sogni. Per ogni strato di noodles della lasagna ti servono 3 noodles. Per ogni strato di salsa ti servono 0,2 litri di salsa.
Definisci la funzione quantities che prende un parametro variadico di tipo String, layers, in cui elenchi i diversi strati della lasagna.
La funzione determinerà poi la quantità di noodles e salsa necessaria per preparare il pasto. Il risultato va restituito in una tupla di tipo (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)
Purtroppo la salsa che hai a disposizione ha il volume indicato in once liquide invece che in litri.
Per aiutarti a capire se hai abbastanza salsa a disposizione, scrivi una funzione toOz che prende un parametro tupla in-out, (noodles: Int, sauce: Double), e converte la quantità di salsa in once liquide.
Tieni presente che un litro corrisponde a 33,814 once liquide.
var amount = (noodles: 9, sauce: 0.8)
toOz(&amount)
amount
// Returns (noodles: 9, sauce: 27.0512)
Infine, vuoi sapere che tipo di vino servire con la lasagna.
Hai sentito dire che si dovrebbe servire vino bianco se nella lasagna ci sono più mozzarella, ricotta e besciamella che carne e salsa, e vino rosso altrimenti.
Scrivi una funzione redWine che prende un parametro variadico di tipo String, layers, in cui elenchi i diversi strati della lasagna.
La funzione userà cinque funzioni annidate per determinare il numero di strati di mozzarella, ricotta, besciamella, salsa e carne nella lasagna, e confronterà i numeri di strati per stabilire se servire il vino rosso, restituendo true in tal caso e false altrimenti.
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
Iscriviti a Exercism per imparare e padroneggiare Swift con 35 concetti116 esercizi e il mentoring di persone reali, tutto gratis.