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.
mod sala;
pub use crate::sala::accoglienza;
pub fn mangiare_al_ristorante() {
accoglienza::aggiungi_in_lista();
}
sala
il cui corpo sarà in src/sala.rsOra, 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
.
pub mod accoglienza {
pub fn aggiungi_in_lista() {}
}
sala
in src/sala.rsNota 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
:
pub mod accoglienza;
Poi creiamo una cartella src/sala e un file accoglienza.rs per contenere le
definizioni del modulo accoglienza
:
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.
Riepilogo
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.