Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Separare i Moduli in File Diversi

Finora tutti gli esempi di questo capitolo definivano più moduli in un unico file. Quando i moduli diventano grandi, potresti voler spostare le loro definizioni in file separati per rendere il codice più facile da navigare.

Per esempio, partiamo dal codice nel Listato 7-17 che aveva più moduli del ristorante. Metteremo ogni modulo in un file invece di avere tutte le definizioni nella radice del crate. In questo caso, il file radice del crate è src/lib.rs, ma questa procedura funziona anche con crate binari il cui file radice è src/main.rs.

Per prima cosa spostiamo il modulo sala in un proprio file. Rimuovi il codice dentro le parentesi graffe del modulo sala, lasciando solo la dichiarazione mod sala;, così che src/lib.rs contenga il codice mostrato nel Listato 7-21. Nota che questo non compilerà finché non creiamo il file src/sala.rs mostrato nel Listato 7-22.

File: src/lib.rs
mod sala;

pub use crate::sala::accoglienza;

pub fn mangiare_al_ristorante() {
    accoglienza::aggiungi_in_lista();
}
Listato 7-21: Dichiarare il modulo sala il cui corpo sarà in src/sala.rs

Ora, metti il codice che era dentro le parentesi graffe in un nuovo file chiamato src/sala.rs, come mostrato nel Listato 7-22. Il compilatore sa di dover cercare in questo file perché ha incontrato la dichiarazione del modulo nella radice del crate con il nome sala.

File: src/sala.rs
pub mod accoglienza {
    pub fn aggiungi_in_lista() {}
}
Listato 7-22: Definizioni all’interno del modulo sala in src/sala.rs

Nota che è necessario caricare un file usando una dichiarazione mod una sola volta nell’albero dei moduli. Una volta che il compilatore sa che il file fa parte del progetto (e sa dove si trova nell’albero dei moduli grazie a dove hai messo la dichiarazione mod), gli altri file del progetto dovrebbero riferirsi al codice del file caricato usando un path verso il punto in cui è stato dichiarato, come trattato nella sezione “Percorsi per fare riferimento a un elemento nell’albero dei moduli”. In altre parole, mod non è un’operazione di “include” come potresti aver visto in altri linguaggi.

Successivamente, sposteremo il modulo accoglienza in un suo file. Il processo è un po’ diverso perché accoglienza è un modulo figlio di sala, non della radice. Metteremo il file per accoglienza in una nuova cartella che sarà chiamata come i suoi antenati nell’albero dei moduli, in questo caso src/sala.

Per iniziare a spostare accoglienza, cambiamo src/sala.rs in modo che contenga solo la dichiarazione del modulo accoglienza:

File: src/sala.rs
pub mod accoglienza;

Poi creiamo una cartella src/sala e un file accoglienza.rs per contenere le definizioni del modulo accoglienza:

File: src/sala/accoglienza.rs
pub fn aggiungi_in_lista() {}

Se invece mettessimo accoglienza.rs nella cartella src, il compilatore si aspetterebbe che il codice di accoglienza.rs sia in un modulo accoglienza dichiarato nella radice del crate, e non come figlio del modulo sala. Le regole del compilatore su quali file cercare per il codice di quali moduli fanno sì che cartelle e file rispecchino più da vicino l’albero dei moduli.

Percorsi di File Alternativi

Finora abbiamo coperto i percorsi di file più idiomatici che il compilatore Rust usa, ma Rust supporta anche uno stile più vecchio. Per un modulo chiamato sala dichiarato nella radice del crate, il compilatore cercherà il codice del modulo in:

  • src/sala.rs (quello che abbiamo visto)
  • src/sala/mod.rs (stile più vecchio, ancora supportato)

Per un modulo chiamato accoglienza che è un sotto-modulo di sala, il compilatore cercherà il codice del modulo in:

  • src/sala/accoglienza.rs (quello che abbiamo visto)
  • src/sala/accoglienza/mod.rs (stile più vecchio, ancora supportato)

Se usi entrambi gli stili per lo stesso modulo, otterrai un errore del compilatore. Usare una combinazione di stili diversi per moduli differenti nello stesso progetto è permesso, ma potrebbe confondere chi oltre a te prende in mano il progetto.

Lo svantaggio principale dello stile con file chiamati mod.rs è che il progetto può finire con molti file chiamati mod.rs, il che può diventare confusionario quando li hai aperti contemporaneamente nell’editor.

Abbiamo spostato il codice di ogni modulo in file separati e l’albero dei moduli rimane lo stesso. Le chiamate di funzione in mangiare_al_ristorante funzioneranno senza alcuna modifica, anche se le definizioni vivono in file diversi. Questa tecnica ti permette di muovere i moduli in nuovi file man mano che crescono di dimensione.

Nota che la dichiarazione pub use crate::sala::accoglienza in src/lib.rs non è cambiata, né use ha alcun impatto su quali file vengono compilati come parte del crate. La parola chiave mod dichiara moduli, e Rust cerca in un file con lo stesso nome del modulo il codice che va in quel modulo.

Rust ti permette di dividere un pacchetto in più crate e un crate in moduli così da poter riferire elementi definiti in un modulo da un altro modulo. Puoi farlo specificando path assoluti o relativi. Questi path possono essere portati nello scope con una dichiarazione use così da poter usare un path più corto per usi ripetuti dell’elemento in quello scope. Il codice dei moduli è privato per default, ma puoi rendere le definizioni pubbliche aggiungendo la parola chiave pub.

Nel prossimo capitolo vedremo alcune strutture dati di collezione nella libreria standard che puoi usare per rendere ancor più ordinato il tuo codice.