Omówienie pojęć związanych z organizacją kodu

Ukończone

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.rstylko 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.