Definire i Moduli per Controllare Scope e Privacy
In questa sezione, parleremo di moduli e altre parti del sistema dei moduli,
ovvero i paths, che ti permettono di nominare gli elementi; la parola
chiave use
che porta un path nello scope; e la parola chiave pub
per rendere
pubblici gli elementi. Discuteremo anche della parola chiave as
, dei pacchetti
esterni e dell'operatore glob.
Scheda di Riferimento dei Moduli
Prima di passare ai dettagli dei moduli e dei paths, forniamo un rapido
riferimento su come funzionano moduli, paths, la parola chiave use
e la
parola chiave pub
nel compilatore, e come la maggior parte degli sviluppatori
organizza il proprio codice. Esamineremo esempi di ciascuna di queste regole
lungo questo capitolo, ma questo è un ottimo posto a cui fare riferimento come
promemoria di come funzionano i moduli.
- Inizia dalla radice del crate: Quando si compila un crate, il compilatore guarda prima nel file radice del crate (di solito src/lib.rs per un crate di libreria o src/main.rs per un crate binario) per del codice da compilare.
- Dichiarare moduli: Nel file radice del crate, puoi dichiarare nuovi moduli;
supponi di dichiarare un modulo "garden" con
mod garden;
. Il compilatore cercherà il codice del modulo in questi posti:- In linea, all'interno di parentesi graffe che sostituiscono il punto e
virgola che segue
mod garden
- Nel file src/garden.rs
- Nel file src/garden/mod.rs
- In linea, all'interno di parentesi graffe che sostituiscono il punto e
virgola che segue
- Dichiarare sottomoduli: In qualsiasi file diverso dalla radice del crate,
puoi dichiarare sottomoduli. Ad esempio, potresti dichiarare
mod vegetables;
in src/garden.rs. Il compilatore cercherà il codice del sottomodulo all'interno della directory nominata per il modulo genitore in questi posti:- In linea, immediatamente dopo
mod vegetables
, all'interno di parentesi graffe invece del punto e virgola - Nel file src/garden/vegetables.rs
- Nel file src/garden/vegetables/mod.rs
- In linea, immediatamente dopo
- Paths al codice nei moduli: Una volta che un modulo fa parte del tuo crate,
puoi fare riferimento al codice in quel modulo da qualsiasi altra parte nello stesso crate,
fintanto che le regole di privacy lo consentono, usando il path al codice.
Ad esempio, un tipo
Asparagus
nel modulo delle verdure del giardino sarebbe trovato acrate::garden::vegetables::Asparagus
. - Privato vs. pubblico: Il codice all'interno di un modulo è privato rispetto
ai suoi moduli genitori per impostazione predefinita. Per rendere un modulo
pubblico, dichiaralo con
pub mod
invece dimod
. Per rendere pubblici gli elementi all'interno di un modulo pubblico, usapub
prima delle loro dichiarazioni. - La parola chiave
use
: All'interno di uno scope, la parola chiaveuse
crea scorciatoie per gli elementi per ridurre la ripetizione di paths lunghi. In qualsiasi scope che può fare riferimento acrate::garden::vegetables::Asparagus
, puoi creare una scorciatoia conuse crate::garden::vegetables::Asparagus;
e da quel momento in poi devi solo scrivereAsparagus
per utilizzare quel tipo nello scope.
Qui, creiamo un crate binario chiamato backyard
che illustra queste regole.
La directory del crate, anch'essa chiamata backyard
, contiene questi file e
directory:
backyard
├── Cargo.lock
├── Cargo.toml
└── src
├── garden
│ └── vegetables.rs
├── garden.rs
└── main.rs
Il file radice del crate in questo caso è src/main.rs, e contiene:
Nome del file: src/main.rs
use crate::garden::vegetables::Asparagus;
pub mod garden;
fn main() {
let plant = Asparagus {};
println!("I'm growing {:?}!", plant);
}
La linea pub mod garden;
dice al compilatore di includere il codice che trova
in src/garden.rs, che è:
Nome del file: src/garden.rs
pub mod vegetables;
Qui, pub mod vegetables;
significa che anche il codice in
src/garden/vegetables.rs è incluso. Quel codice è:
#[derive(Debug)]
pub struct Asparagus {}
Ora entriamo nei dettagli di queste regole e dimostriamole in azione!
Raggruppare Codice Correlato in Moduli
I moduli ci permettono di organizzare il codice all'interno di un crate per leggibilità e facile riutilizzo. I moduli ci permettono anche di controllare la privacy degli elementi poiché il codice all'interno di un modulo è privato per impostazione predefinita. Gli elementi privati sono dettagli di implementazione interni non disponibili per uso esterno. Possiamo scegliere di rendere pubblici i moduli e gli elementi al loro interno, esponendoli per permettere al codice esterno di utilizzarli e dipenderne.
Come esempio, scriviamo un crate di libreria che fornisce la funzionalità di un ristorante. Definiremo le firme delle funzioni ma lasceremo vuoti i loro blocchi per concentrarci sull'organizzazione del codice piuttosto che sull'implementazione di un ristorante.
Nell'industria della ristorazione, alcune parti di un ristorante sono denominate front of house e altre back of house. Front of house è dove si trovano i clienti; questo comprende dove i promotori siedono i clienti, i camerieri prendono ordini e pagamenti, e i baristi fanno i drink. Back of house è dove gli chef e i cuochi lavorano in cucina, i lavapiatti puliscono, e i manager svolgono lavori amministrativi.
Per strutturare il nostro crate in questo modo, possiamo organizzare le sue
funzioni in moduli annidati. Crea una nuova libreria chiamata restaurant
eseguendo cargo new restaurant --lib
. Quindi inserisci il codice nel
Listing 7-1 in src/lib.rs per definire alcuni moduli e le firme delle
funzioni; questo codice rappresenta la sezione front of house.
Nome del file: src/lib.rs
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
Definiamo un modulo con la parola chiave mod
seguita dal nome del modulo
(in questo caso, front_of_house
). Il corpo del modulo va quindi all'interno
di parentesi graffe. All'interno dei moduli, possiamo inserire altri moduli,
come in questo caso con i moduli hosting
e serving
. I moduli possono anche
contenere definizioni per altri elementi, come struct, enum, costanti, traits, e—
come nel Listing 7-1—funzioni.
Usando i moduli, possiamo raggruppare insieme definizioni correlate e nominare perché sono correlate. I programmatori che usano questo codice possono navigare il codice basandosi sui gruppi piuttosto che dover leggere tutte le definizioni, rendendo più facile trovare le definizioni rilevanti per loro. I programmatori che aggiungono nuova funzionalità a questo codice saprebbero dove posizionare il codice per mantenere il programma organizzato.
In precedenza, abbiamo menzionato che src/main.rs e src/lib.rs sono
chiamati radici del crate. Il motivo del loro nome è che i contenuti di uno
qualsiasi di questi due file formano un modulo denominato crate
alla radice
della struttura del modulo del crate, conosciuta come albero dei moduli.
Il Listing 7-2 mostra l'albero dei moduli per la struttura nel Listing 7-1.
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
Questo albero mostra come alcuni moduli si annidano all'interno di altri moduli; ad esempio,
hosting
si annida all'interno di front_of_house
. L'albero mostra anche che
alcuni moduli sono fratelli, nel senso che sono definiti nello stesso modulo;
hosting
e serving
sono fratelli definiti all'interno di front_of_house
.
Se il modulo A è contenuto all'interno del modulo B, diciamo che il modulo A è
il figlio del modulo B e che il modulo B è il genitore del modulo A. Nota
che l'intero albero dei moduli è radicato sotto il modulo implicito denominato crate
.
L'albero dei moduli potrebbe ricordarti l'albero delle directory del filesystem sul tuo computer; questo è un confronto molto adeguato! Proprio come le directory in un filesystem, usi i moduli per organizzare il tuo codice. E proprio come i file in una directory, abbiamo bisogno di un modo per trovare i nostri moduli.