Salta ai contenuti

Variabili in Rust

Una variabile è semplicemente un nome che dai a un valore per poterlo usare più tardi. Pensala come una scatola con un’etichetta: ci metti dentro qualcosa, ci scrivi sopra un nome, e la chiami con quel nome invece di ripetere il valore dappertutto.

In Rust crei una variabile con la parola chiave let:

fn main() {
let age = 30;
println!("Ho {age} anni");
}

Output:

Ho 30 anni
▶ Provalo tu

Smontiamo quella riga:

  • let: dice a Rust «sto creando una nuova variabile».
  • age: il nome che abbiamo scelto.
  • =: assegna il valore a destra al nome a sinistra.
  • 30: il valore che stiamo salvando.

L’{age} dentro println! stampa il valore della variabile. Si chiama interpolazione di stringhe: Rust sostituisce {age} con quello che contiene age.

Ogni valore in Rust ha un tipo (un numero intero, del testo, true/false e così via). Potresti aspettarti di doverlo dichiarare, ma di solito non serve: Rust guarda il valore e lo deduce da solo. Si chiama inferenza di tipo.

fn main() {
let score = 95; // Rust deduce che è un intero
let name = "Ferris"; // Rust deduce che è testo
let is_active = true; // Rust deduce che è un booleano
println!("{name}: {score}, attivo = {is_active}");
}

Output:

Ferris: 95, attivo = true
▶ Provalo tu

Se vuoi essere esplicito, puoi scrivere il tipo dopo i due punti:

let score: i32 = 95; // i32 = un intero a 32 bit

Ecco la parte che sorprende chi arriva da altri linguaggi: in Rust, una volta assegnata una variabile, per default non puoi cambiarla. «Immutabile» significa proprio che non si può cambiare.

Questo codice non compila:

fn main() {
let count = 1;
count = 2; // ❌ errore: non puoi assegnare due volte una variabile immutabile
println!("{count}");
}

Il compilatore ti ferma con un messaggio chiaro:

error[E0384]: cannot assign twice to immutable variable `count`

Cioè: non puoi assegnare due volte la variabile immutabile count.

Perché un linguaggio dovrebbe farlo apposta? Perché tanti bug nascono da valori che cambiano quando non te lo aspetti. Rendendo le cose immutabili a meno che tu non chieda di poterle cambiare, Rust rende il tuo codice più prevedibile. È una caratteristica, non un limite.

Quando hai davvero bisogno che un valore cambi, aggiungi la parola chiave mut (abbreviazione di mutable, cioè modificabile):

fn main() {
let mut count = 1;
println!("Prima: {count}");
count = 2; // ✅ ora è permesso, grazie a `mut`
println!("Dopo: {count}");
}

Output:

Prima: 1
Dopo: 2
▶ Provalo tu

Rust ti permette di dichiarare una variabile nuova con lo stesso nome di una vecchia. Si chiama shadowing (oscuramento): la nuova «fa ombra» alla vecchia:

fn main() {
let x = 5;
let x = x + 1; // una nuova x, basata sulla vecchia x -> 6
let x = x * 2; // un'altra nuova x -> 12
println!("x vale {x}");
}

Output:

x vale 12
▶ Provalo tu

Sembra simile a mut, ma è diverso:

  • mut cambia il valore della stessa variabile.
  • Lo shadowing crea una variabile completamente nuova che riusa il nome, e può perfino avere un tipo diverso.

Lo shadowing è comodo quando vuoi trasformare un valore ma continuare a usare lo stesso nome:

fn main() {
let spaces = " "; // testo
let spaces = spaces.len(); // ora è un numero (quanti spazi)
println!("Numero di spazi: {spaces}");
}

Output:

Numero di spazi: 3
▶ Provalo tu

Una costante è un valore che non cambia mai ed è fissato in fase di compilazione. La dichiari con const invece di let, e devi scrivere il tipo:

const MAX_SCORE: u32 = 100;
fn main() {
println!("Il punteggio massimo è {MAX_SCORE}");
}

Output:

Il punteggio massimo è 100
▶ Provalo tu

Per convenzione, le costanti si scrivono in UPPER_SNAKE_CASE. Ecco come si confrontano con le variabili normali:

Variabile let Costante const
Può cambiare? Solo con mut Mai
Tipo obbligatorio? Facoltativo (dedotto) Obbligatorio
Stile del nome snake_case UPPER_SNAKE_CASE
Dove si può usare Dentro le funzioni Ovunque, anche fuori dalle funzioni

Usa una costante per valori davvero fissi, come il numero di secondi in un minuto o un limite massimo.

  • Usa lo snake_case: parole minuscole unite da trattini bassi, come user_name, total_price.
  • I nomi possono contenere lettere, numeri e trattini bassi, ma non possono cominciare con un numero.
  • Scegli nomi descrittivi: age è meglio di a.

Crea una variabile level che parte da 1. Stampala, aumentala di 1 due volte e stampala dopo ogni modifica, così ottieni Livello 1, Livello 2, Livello 3. Suggerimento: un valore che cambia ha bisogno di mut, e level = level + 1; aggiunge uno.

Mostra la soluzione
fn main() {
let mut level = 1;
println!("Livello {level}");
level = level + 1;
println!("Livello {level}");
level = level + 1;
println!("Livello {level}");
}

Output:

Livello 1
Livello 2
Livello 3
▶ Provalo tu

Dichiara una costante SECONDS_PER_MINUTE uguale a 60. Parti da let time = 5; (in minuti), poi fai lo shadowing di time in modo che contenga la stessa durata in secondi, e stampa Sono 300 secondi. Suggerimento: la nuova time si può costruire dalla vecchia: let time = time * ...;.

Mostra la soluzione
const SECONDS_PER_MINUTE: u32 = 60;
fn main() {
let time = 5; // minuti
let time = time * SECONDS_PER_MINUTE; // una nuova `time`, ora in secondi
println!("Sono {time} secondi");
}

Output:

Sono 300 secondi
▶ Provalo tu

Non serve mut: il secondo let crea una variabile completamente nuova che riusa il nome. Qui Rust deduce anche che time è un u32, perché viene moltiplicata per la costante u32.

  • Crea le variabili con let; di solito Rust deduce il tipo al posto tuo.
  • Le variabili sono immutabili per default: aggiungi mut per permettere le modifiche.
  • Lo shadowing dichiara di nuovo un nome con let, creando una nuova variabile (che può cambiare tipo).
  • Le costanti (const) non cambiano mai, hanno sempre bisogno di un tipo e usano lo UPPER_SNAKE_CASE.

Verifica veloce

1. Per default, puoi riassegnare una variabile let in Rust?

2. Cos'è lo shadowing in Rust?

3. Secondo questa pagina, quale convenzione di nomi usano le variabili in Rust?

Punteggio: 0 / 3