Introdução
À medida que um programa Rust cresce, manter todos os tipos e funções em um único arquivo dificulta a visualização das responsabilidades. Você já viu uma biblioteca e um binário no Lab de CLI, além de um módulo de testes no Lab de testes. Agora, este Lab conecta esses exemplos preparados em um único modelo: um pacote é o projeto que o Cargo compila, crates são unidades de compilação e módulos organizam os nomes dentro de uma crate.
Você vai organizar um pequeno pacote de relatório de despensa. Os arquivos e a maior parte do código de implementação já estão preparados, portanto cada etapa se concentra em um limite: compartilhar algo a partir da crate de biblioteca, declarar um módulo em arquivo e importar uma pequena API pública para a crate binária.
Compartilhe uma função entre crates
Nesta etapa, você identificará as duas crates do pacote e disponibilizará uma função da biblioteca para o binário.
Acesse o pacote Cargo preparado:
cd /home/labex/project/pantry-report
Cargo.toml descreve um pacote chamado pantry-report. O Cargo reconhece src/lib.rs como a raiz de uma crate de biblioteca e src/main.rs como a raiz de uma crate binária. Elas pertencem ao mesmo pacote, mas são compiladas como crates separadas.
Inspecione as raízes curtas das crates. Os comandos sed -n exibem os intervalos de linhas solicitados sem editar os arquivos:
sed -n '1,120p' src/lib.rs
sed -n '1,120p' src/main.rs
O binário importa report_title usando o caminho da crate de biblioteca. Um nome de pacote que contém hífen se torna um nome de crate que contém sublinhado no código-fonte Rust; portanto, pantry-report se torna pantry_report.
O tipo de retorno preparado, &'static str, descreve uma referência emprestada a um literal de string que permanece válido durante todo o programa. O marcador 'static é uma anotação de tempo de vida. As regras explícitas de tempo de vida estão intencionalmente fora do escopo deste curso introdutório; nenhuma alteração feita pelo aluno neste Lab depende de entender ou escrever uma.
Os itens são privados para o módulo, a menos que sejam marcados com pub. Abra a raiz da biblioteca:
nano src/lib.rs
Altere somente a declaração da função, de:
fn report_title() -> &'static str {
para:
pub fn report_title() -> &'static str {
pub torna a função parte da interface pública da crate de biblioteca. Salve com Ctrl+O, pressione Enter e saia com Ctrl+X.
Use cargo check para verificar os tipos das duas crates sem produzir uma compilação final executável:
cargo check
Depois, execute a crate binária:
cargo run --quiet
A saída é:
Pantry Report
Isso comprova que o binário consegue atravessar o limite da crate e chamar a função pública da biblioteca.
Declare um módulo em um arquivo
Nesta etapa, você conectará o arquivo inventory.rs preparado à árvore de módulos da crate de biblioteca.
Um arquivo-fonte Rust não é compilado apenas porque existe. A raiz da crate precisa declarar o módulo. Para uma declaração chamada inventory, o Rust procura src/inventory.rs e coloca seus itens sob o caminho inventory::....
Inspecione o arquivo de módulo preparado. Como antes, sed -n '1,200p' usa -n para suprimir a saída automática, enquanto 1,200p imprime somente o intervalo de linhas solicitado:
sed -n '1,200p' src/inventory.rs
A linha #[derive(Debug)] solicita que o Rust gere suporte padrão para formatação de depuração para Item. O programa visível não depende desse recurso; portanto, considere-o metadado preparado, e não um novo requisito. O tipo Item, seus campos e describe são públicos. O auxiliar availability não tem pub, então continua privado dentro do módulo. describe pode chamar esse auxiliar privado, enquanto os chamadores externos recebem apenas o resultado público.
Abra a raiz da biblioteca:
nano src/lib.rs
Substitua // MODULE_DECLARATION por:
pub mod inventory;
O primeiro pub expõe o módulo por meio da crate de biblioteca. A parte mod inventory; conecta o arquivo à árvore de módulos. Salve e saia do Nano; em seguida, verifique o pacote:
cargo check
Finished `dev` profile ...
A verificação bem-sucedida comprova que o Rust encontrou src/inventory.rs e o compilou como pantry_report::inventory.
Importe e use a API pública
Nesta etapa, você usará uma declaração use para trazer itens do módulo para a crate binária e imprimir um registro da despensa.
Sem uma importação, os caminhos completos são pantry_report::inventory::Item e pantry_report::inventory::describe. Uma declaração use cria nomes mais curtos no escopo atual sem mover nem copiar os itens.
Abra o código-fonte do binário:
nano src/main.rs
Substitua // INVENTORY_IMPORT por esta importação agrupada:
use pantry_report::inventory::{describe, Item};
As chaves agrupam dois itens que compartilham o mesmo prefixo de caminho. Em seguida, substitua // INVENTORY_REPORT por:
let lentils = Item {
name: String::from("lentils"),
quantity: 4,
};
println!("{}", describe(&lentils));
O binário pode criar Item porque o tipo e os dois campos são públicos. Ele empresta o item para describe; essa função pública chama privadamente availability dentro do próprio módulo.
Salve e saia do Nano; depois, execute o pacote:
cargo run --quiet
Pantry Report
lentils: 4 jars (stocked)
As duas linhas mostram que tanto o compartilhamento no nível da crate quanto a organização no nível do módulo estão funcionando por meio de uma pequena API pública.
Resumo
Você trabalhou com um pacote Cargo contendo crates de biblioteca e binária, tornou público um item da biblioteca, declarou um módulo em arquivo, seguiu caminhos de crates e módulos, encurtou esses caminhos com use e manteve um auxiliar de implementação privado por trás de uma pequena API pública.


