00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Scope delle Variabili in Rust

In Rust, lo scope di una variabile determina dove è accessibile e quando viene deallocata. Il sistema di ownership si basa fondamentalmente sugli scope.

Scope di Blocco

Ogni coppia di {} crea un nuovo scope. Le variabili vengono rilasciate (drop) alla fine del blocco:

fn main() {
    let x = 5;

    {
        let y = 10;
        println!("{} {}", x, y); // OK: entrambe visibili
    } // y viene rilasciata qui

    println!("{}", x); // OK
    // println!("{}", y); // ERRORE: y non esiste più
}

Ownership e Scope

Quando una variabile esce dallo scope, Rust chiama automaticamente drop:

fn main() {
    {
        let s = String::from("ciao"); // s entra nello scope
        println!("{}", s);
    } // s esce dallo scope e la memoria viene liberata

    // s non è più accessibile qui
}

Move e Scope

Con il move semantics, l’ownership viene trasferita:

fn main() {
    let s1 = String::from("ciao");
    let s2 = s1; // s1 viene "moved" in s2

    // println!("{}", s1); // ERRORE: s1 non è più valida
    println!("{}", s2); // OK
}

Scope nelle Funzioni

I parametri entrano nello scope della funzione e ne escono alla fine:

fn prendi_ownership(s: String) {
    println!("{}", s);
} // s viene rilasciata qui

fn solo_riferimento(s: &String) {
    println!("{}", s);
} // s (il riferimento) esce dallo scope, ma il dato originale no

fn main() {
    let s = String::from("ciao");
    solo_riferimento(&s); // Prestito: s resta valida
    prendi_ownership(s);   // Move: s non è più valida
    // println!("{}", s);  // ERRORE
}

Scope nei Condizionali e Cicli

fn main() {
    let condizione = true;

    if condizione {
        let temporanea = String::from("esiste solo qui");
        println!("{}", temporanea);
    } // temporanea rilasciata

    for i in 0..3 {
        let elemento = format!("item_{}", i);
        println!("{}", elemento);
    } // elemento rilasciata ad ogni iterazione
}

Il Trait Drop

Puoi personalizzare il comportamento alla fine dello scope:

struct Risorsa {
    nome: String,
}

impl Drop for Risorsa {
    fn drop(&mut self) {
        println!("Rilascio risorsa: {}", self.nome);
    }
}

fn main() {
    let r1 = Risorsa { nome: "file.txt".into() };
    let r2 = Risorsa { nome: "connessione".into() };
    println!("Risorse create");
} // Stampa: Rilascio risorsa: connessione, poi: Rilascio risorsa: file.txt
// L'ordine di drop è inverso rispetto alla dichiarazione (LIFO)

Drop Anticipato

fn main() {
    let r = Risorsa { nome: "lock".into() };
    // ... usa la risorsa ...
    drop(r); // Rilascia esplicitamente prima della fine dello scope
    // ... altro codice che non ha bisogno della risorsa ...
}

Conclusione

Lo scope in Rust è strettamente legato al sistema di ownership. Le variabili vengono automaticamente deallocate alla fine del loro scope, eliminando la necessità di gestione manuale della memoria. Questo meccanismo RAII (Resource Acquisition Is Initialization) garantisce che le risorse vengano sempre rilasciate correttamente.