Omówienie pojęć związanych z organizacją kodu
Przed rozpoczęciem należy wyjaśnić pojęcia związane z organizacją kodu w programach Rust:
- Pakiet:
- Zawiera funkcje w co najmniej jednej skrzyni.
- Zawiera informacje o sposobie tworzenia tych skrzynek. Informacje są w
Cargo.toml
pliku.
- Skrzynia:
- Jest jednostką kompilacji, która jest najmniejszą ilością kodu, na której może działać kompilator Rust.
- Po skompilowaniu tworzy plik wykonywalny lub bibliotekę.
- Zawiera niejawny, nienazwany moduł najwyższego poziomu.
- Moduł:
- Jest (prawdopodobnie zagnieżdżona) jednostką organizacji kodu wewnątrz skrzyni.
- Może mieć definicje cykliczne obejmujące dodatkowe moduły.
Pakiet
Za każdym razem, gdy uruchamiamy polecenie $ cargo new <project-name>
, ładunek tworzy dla nas pakiet:
$ cargo new my-project
Created binary (application) `my-project` package
W tym miejscu mamy pakiet, który zawiera src/main.rs
tylko element , co oznacza, że zawiera tylko binarną skrzynię o nazwie my-project
:
my-project
├── src
│ └── main.rs
└── Cargo.toml
Pakiet może zawierać wiele binarnych skrzynek, umieszczając pliki w src/bin
katalogu. Każdy plik będzie oddzielną skrzynią binarną.
Jeśli pakiet zawiera src/main.rs
i src/lib.rs
, ma dwie skrzynie: bibliotekę i plik binarny. Oba mają taką samą nazwę jak pakiet.
Skrzynie
Model kompilacji Rust koncentruje się na artefaktach nazywanych skrzyniami , które można skompilować do pliku binarnego lub do biblioteki.
Każdy projekt tworzony za cargo new
pomocą polecenia jest samą skrzynią. Każdy kod Rust innej firmy, którego można użyć jako zależności w projekcie, jest również jedną skrzynią.
Skrzynie biblioteki
Omówiliśmy już sposób tworzenia programu binarnego i tworzenie biblioteki jest równie proste. Aby utworzyć bibliotekę, przekaż --lib
parametr wiersza polecenia do cargo new
polecenia:
$ cargo new --lib my-library
Created library `my-library` package
Widać, że zamiast src/main.rs
pliku uzyskasz teraz plik =src/lib.rs.
my-library
├── src
│ └── lib.rs
└── Cargo.toml
Po utworzeniu tej skrzyni ładunku otrzymasz plik biblioteki o nazwie libmy_library.rlib
, który można opublikować i połączyć z innymi projektami.
Moduły
Rust udostępnia zaawansowany system modułów, który może służyć do hierarchicznego dzielenia kodu na jednostki logiczne, które ułatwiają również czytelność i ponowne użycie.
Moduł to kolekcja elementów:
- Stałe
- Aliasy typów
- Funkcje
- Struktury
- Wyliczenia
- Cechy
impl
Bloki- Inne moduły
Moduły kontrolują również prywatność elementów. Prywatność elementu identyfikuje element jako publiczny lub prywatny. Publiczne oznacza, że element może być używany przez kod zewnętrzny. Prywatny oznacza, że element jest szczegółem implementacji wewnętrznej i nie jest dostępny do użytku zewnętrznego.
Przykład modułu:
mod math {
type Complex = (f64, f64);
pub fn sin(f: f64) -> f64 { /* ... */ }
pub fn cos(f: f64) -> f64 { /* ... */ }
pub fn tan(f: f64) -> f64 { /* ... */ }
}
println!("{}", math::cos(45.0));
Jeśli plik źródłowy zawiera mod
deklaracje, zawartość plików modułu zostanie wstawiona w miejscach, w których mod
znajdują się deklaracje w pliku źródłowym, przed uruchomieniem kompilatora. Innymi słowy, moduły nie są kompilowane indywidualnie, tylko skrzynie są kompilowane.
Być może słowo kluczowe na pub
początku definicji funkcji w math
module zostało zauważone.
Kompilator Rust sprawdza, czy elementy mogą być używane w modułach, czy nie. Domyślnie wszystko w języku Rust jest prywatne i może być dostępne tylko przez bieżący moduł i jego elementy podrzędne. Natomiast gdy element jest zadeklarowany jako pub
, można go traktować jako dostęp do świata zewnętrznego. Na przykład:
// Declare a private struct
struct Foo;
// Declare a public struct with a private field
pub struct Bar {
field: i32,
}
// Declare a public enum with two public variants
pub enum State {
PubliclyAccessibleVariant,
PubliclyAccessibleVariant2,
}
Reguły prywatności rusta są zaskakująco zaawansowane w przypadku tworzenia hierarchii modułów uwidaczniających publiczne interfejsy API podczas ukrywania wewnętrznych szczegółów implementacji.