Rust: main.rs e lib.rs — como não se confundir com módulos e acelerar o código

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Confusão com módulos Rust: como main.rs e lib.rs enlouquecem (e como corrigir isso)

\n\n

Você já escreveu em Rust, criou um novo projeto, adicionou main.rs e lib.rs — e de repente o compilador começou a dar erros que pareciam não fazer sentido? Familiar? Se você pesquisou no Google "Rust modules confusion when there is main.rs and lib.rs", você não está sozinho. Essa pergunta no Stack Overflow acumulou milhares de visualizações, e não é à toa. A confusão com módulos é um dos problemas mais comuns entre iniciantes (e até mesmo desenvolvedores experientes vindos de outras linguagens).

\n\n

Neste artigo, não vamos apenas analisar como o sistema de módulos do Rust funciona. Vamos mostrar como a sua organização correta impacta diretamente a otimização e o desempenho do seu código. Você descobrirá por que lib.rs não é apenas "mais um arquivo", mas uma ferramenta poderosa para acelerar a compilação e criar uma API limpa. Vamos lá!

\n\n

O problema: "Por que o compilador não vê meus módulos?"

\n\n

Imagine: você criou um projeto my_project com cargo new my_project. Por padrão, o Cargo cria src/main.rs. Você adiciona um segundo arquivo — src/lib.rs — e escreve uma função nele. Depois tenta chamá-la a partir de main.rs — e recebe o erro:

\n\n
error[E0432]: unresolved import `my_project::some_function`\n --> src/main.rs:1:5\n  |\n1 | use my_project::some_function;\n  |     ^^^^^^^^^^^^^^^^^^^^^^^^^ no `some_function` in the root
\n\n

Dor familiar? Qual é o problema? Simples: Rust considera main.rs e lib.rs como duas raízes de crate diferentes. Se nada diferente for especificado em Cargo.toml, o Cargo cria automaticamente dois crates: um binário (a partir de main.rs) e um de biblioteca (a partir de lib.rs). Eles não se "enxergam" diretamente, a menos que você declare explicitamente as dependências.

\n\n

Esta é a tal Rust modules confusion de que todos falam. Mas, em vez de ficar irritado, vamos transformar essa "peculiaridade" em uma vantagem.

\n\n

A solução: como organizar os módulos corretamente

\n\n

Existem duas abordagens, e a escolha depende do seu objetivo. Mas já vamos dar um spoiler: a segunda abordagem é melhor para o desempenho.

\n\n

Opção 1: Tudo em um único crate (simples, mas não escalável)

\n\n

Se o seu projeto for pequeno, você pode declarar os módulos dentro de main.rs usando mod:

\n\n
// src/main.rs\nmod utils; // procura por src/utils.rs ou src/utils/mod.rs\n\nfn main() {\n    utils::do_something();\n}
\n\n

Isso funciona, mas se você adicionar lib.rs, a confusão começa. lib.rs se tornará um crate separado, e os módulos de main.rs não estarão disponíveis nele. Para scripts pequenos — ok, para projetos sérios — não.

\n\n

Opção 2: Biblioteca + binário (o caminho correto para otimização)

\n\n

A maneira mais sensata é fazer de lib.rs o repositório principal da lógica, e main.rs um invólucro fino para execução. Assim você obtém:

\n
    \n
  • Modularidade: toda a lógica de negócios na biblioteca.
  • \n
  • Testabilidade: a biblioteca pode ser testada separadamente.
  • \n
  • Desempenho: o compilador otimiza melhor o código da biblioteca se ele for usado repetidamente.
  • \n
\n\n

Como fazer? Simples:

\n
// src/lib.rs\npub mod utils;\n\npub fn run() {\n    utils::do_something();\n}\n\n// src/main.rs\nfn main() {\n    my_project::run(); // my_project — nome do crate em Cargo.toml\n}
\n\n

Observe: main.rs agora usa my_project::run(). Isso funciona porque o Cargo vê lib.rs como uma biblioteca com o nome my_project. Voilà — a confusão desapareceu!

\n\n

Otimização e desempenho: por que lib.rs é seu amigo

\n\n

Agora, o mais interessante

Blogs

Book Recommendations