Pacotes e Crates
As primeiras partes do sistema de módulos que vamos abordar são pacotes e crates.
Um crate é a menor unidade de código que o compilador Rust considera em um
processo de compilação. Mesmo que você execute rustc diretamente em vez de
usar cargo, passando um único arquivo-fonte, como fizemos em “Noções
Básicas de um Programa Rust” no Capítulo 1, o
compilador trata esse arquivo como um crate. Crates podem conter módulos, e os
módulos podem ser definidos em outros arquivos que são compilados junto com o
crate, como veremos nas próximas seções.
Um crate pode ser de um de dois tipos: crate binário ou crate de biblioteca.
Crates binários são programas que podem ser compilados para um executável, por
exemplo um programa de linha de comando ou um servidor. Cada crate binário
precisa ter uma função chamada main, que define o que acontece quando o
executável é executado. Todos os crates que criamos até agora eram crates
binários.
Crates de biblioteca não têm função main e não são compilados em um
executável. Em vez disso, eles definem funcionalidades destinadas a ser
compartilhadas com outros projetos. Por exemplo, o crate rand, que usamos no
Capítulo 2, fornece funcionalidades para gerar números
aleatórios. Na maior parte do tempo, quando rustaceanos dizem “crate”, eles
estão falando de um crate de biblioteca e usam “crate” quase como sinônimo da
ideia geral de “biblioteca”.
O crate root é o arquivo-fonte a partir do qual o compilador Rust começa a análise e monta a árvore de módulos do crate. Vamos explorar módulos com mais profundidade em “Definindo Módulos para Controlar Escopo e Privacidade”.
Um pacote é um conjunto de um ou mais crates que oferece um grupo de funcionalidades. Um pacote contém um arquivo Cargo.toml que descreve como compilar esses crates. O próprio Cargo é, na verdade, um pacote que contém o crate binário da ferramenta de linha de comando que você usa para construir seu código. O pacote do Cargo também contém um crate de biblioteca do qual esse crate binário depende. Outros projetos podem depender desse crate de biblioteca do Cargo para reutilizar a mesma lógica que a ferramenta de linha de comando usa.
Um pacote pode conter quantos crates binários você quiser, mas no máximo um crate de biblioteca. E todo pacote precisa conter pelo menos um crate, seja ele binário, seja de biblioteca.
Vamos ver o que acontece quando criamos um pacote. Primeiro, executamos o
comando cargo new my-project:
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
Depois de executar cargo new my-project, usamos ls para ver o que o Cargo
criou. No diretório my-project, há um arquivo Cargo.toml, que define o
pacote. Também há um diretório src contendo main.rs. Se você abrir
Cargo.toml no editor, verá que ele não menciona explicitamente
src/main.rs. O Cargo segue uma convenção: src/main.rs é o crate root de
um crate binário com o mesmo nome do pacote. Da mesma forma, se o pacote
contiver src/lib.rs, o Cargo entende que ele também possui um crate de
biblioteca com o mesmo nome do pacote, e que src/lib.rs é o crate root
desse crate. O Cargo passa esses arquivos raiz para o rustc, que então
compila a biblioteca ou o binário.
Aqui, temos um pacote que contém apenas src/main.rs, o que significa que ele
contém apenas um crate binário chamado my-project. Se um pacote contiver
tanto src/main.rs quanto src/lib.rs, ele terá dois crates: um binário e um
de biblioteca, ambos com o mesmo nome do pacote. Um pacote também pode ter
vários crates binários colocando arquivos no diretório src/bin: cada arquivo
nesse diretório será um crate binário separado.