In Rust, assegnare un valore a un nome si chiama binding. I binding sono immutabili a meno che non vengano dichiarati con la parola chiave mut. Poiché Rust è un linguaggio tipizzato staticamente, ogni binding ha un tipo noto in fase di compilazione.
I binding vengono definiti più comunemente con la parola chiave let. Per la maggior parte dei binding, specificare il tipo è facoltativo: l'inferenza di tipo di Rust riesce di solito a dedurre il tipo dal valore. Un binding si presenta così:
// Automatically inferred type
let fingers = 10;
Le funzioni sono elementi. Mentre i binding di solito si riferiscono a un valore particolare, gli elementi si riferiscono a un'unità di organizzazione del codice, tipicamente una funzione o un modulo, disponibile per tutta la durata del programma. Una funzione restituisce automaticamente il risultato della sua ultima espressione. Una funzione può avere zero o più parametri, che sono binding con una durata limitata alla chiamata della funzione.
L'inferenza di tipo sarebbe teoricamente possibile anche per le funzioni, ma è disattivata per una scelta intenzionale di progettazione del linguaggio. Se da un lato questo significa che, quando scrivi il codice, devi dedicare un po' più di tempo a specificare con precisione quali sono i tipi di input e output di una funzione, dall'altro risparmi tempo quando leggi il codice, perché tutti i tipi di input e output sono definiti esplicitamente.
fn add(x: i32, y: i32) -> i32 {
x + y
}
Per chiamare una funzione, scrivi il suo nome seguito da una coppia di parentesi tonde (()). Se la funzione richiede dei parametri, per ciascuno di essi occorre specificare un argomento tra le parentesi.
let five = add(2, 3);
Se il tipo di un binding non può essere dedotto, il compilatore segnala un errore. Per risolvere, aggiungi al binding un'annotazione di tipo esplicita.
// Explicit type annotation
let fingers: i32 = 10;
In Rust, gli elementi possono essere usati prima o dopo essere stati definiti, perché hanno una durata statica. I binding, invece, possono essere usati solo dopo essere stati definiti. Usare un binding prima che sia stato definito provoca un errore di compilazione.
fn main() {
// `fn add` hasn't yet been defined, but that's perfectly ok
dbg!(add(3, 4));
}
fn add(x: i32, y: i32) -> i32 {
x + y
}
// this won't compile; `a` is used before its binding is defined
let b = a;
let a = x + y;
Rust usa le parentesi graffe ({}) per definire uno scope. Un binding definito all'interno di uno scope non può uscirne.
let a = 1;
dbg!(a); // 1
{
// Here, we re-bind `a` to a new value, which is still immutable.
// This technique is called _shadowing_. The new binding is constrained to
// this anonymous scope. Outside this scope, the previous binding still
// applies.
let a = 2;
let b = 3;
dbg!(a, b); // 2, 3
}
// can't use `b` anymore because it is out of scope
// dbg!(b);
// The shadowed `a` in the inner scope above has fallen out of scope,
// leaving us with our original binding.
dbg!(a); // 1
Gli elementi di Rust sono spesso organizzati in moduli. Ogni crate è implicitamente un modulo, ma può definire sotto-moduli interni di profondità arbitraria. Un modulo raggruppa funzionalità correlate e viene definito con la parola chiave mod.
mod calc_i32 {
fn add(a: i32, b: i32) -> i32 { a + b }
fn sub(a: i32, b: i32) -> i32 { a - b }
fn mul(a: i32, b: i32) -> i32 { a * b }
fn div(a: i32, b: i32) -> i32 { a / b }
}
Rust supporta due tipi di commenti. La parola chiave // indica un commento su una sola riga: tutto ciò che segue la parola chiave fino alla fine della riga viene ignorato. Le parole chiave /* e */ indicano un commento su più righe: tutto ciò che si trova tra queste due parole chiave viene ignorato. Preferire i commenti su una sola riga è idiomatico e una buona pratica.
Rust supporta anche i commenti di documentazione, che compaiono nella documentazione generata da cargo doc. I commenti di documentazione esterni si formano con la parola chiave ///, che si comporta esattamente come la parola chiave //. Si applicano all'elemento che li segue, ad esempio una funzione:
/// The `add` function produces the sum of its arguments.
fn add(x: i32, y: i32) -> i32 { x + y }
I commenti di documentazione interni si formano con la parola chiave //!, che si comporta esattamente come la parola chiave //. Si applicano all'elemento che li contiene, ad esempio un modulo:
mod my_cool_module {
//! This module is the bee's knees.
}
I commenti di documentazione possono essere di lunghezza arbitraria e contenere markdown, che viene renderizzato nella documentazione generata.
In questo esercizio scriverai del codice per aiutarti a cucinare una lasagna strepitosa tratta dal tuo libro di cucina preferito.
Hai quattro attività, tutte legate al tempo impiegato per cucinare la lasagna.
Definisci il binding expected_minutes_in_oven per verificare quanti minuti la lasagna deve restare in forno. Secondo il libro di cucina, il tempo previsto in forno è di 40 minuti:
expected_minutes_in_oven()
// Returns: 40
Definisci la funzione remaining_minutes_in_oven che prende come parametro i minuti effettivi che la lasagna è già stata in forno, e restituisce quanti minuti deve ancora rimanere in forno, in base al tempo previsto in forno indicato nell'attività precedente.
remaining_minutes_in_oven(30)
// Returns: 10
Definisci la funzione preparation_time_in_minutes che prende come parametro il numero di strati che hai aggiunto alla lasagna, e restituisce quanti minuti hai impiegato a prepararla, supponendo che ogni strato richieda 2 minuti.
preparation_time_in_minutes(2)
// Returns: 4
Definisci la funzione elapsed_time_in_minutes che prende due parametri: il primo è il numero di strati che hai aggiunto alla lasagna, il secondo è il numero di minuti che la lasagna è stata in forno. La funzione deve restituire quanti minuti hai lavorato per cucinare la lasagna, cioè la somma del tempo di preparazione in minuti e del tempo, in minuti, che la lasagna ha passato in forno fino a quel momento.
elapsed_time_in_minutes(3, 20)
// Returns: 26
Iscriviti a Exercism per imparare e padroneggiare Rust con 99 esercizi e il mentoring di persone reali, tutto gratis.