Módulos em Rust
Até agora, todos os exemplos ficaram em um único arquivo main.rs. Isso funciona bem para programas pequenos, mas projetos de verdade dividem o código em partes que fazem sentido juntas. A ferramenta do Rust para isso é o sistema de módulos: mod, pub e use.
Criando um módulo
Seção intitulada “Criando um módulo”Um módulo é um bloco com nome que agrupa código relacionado:
mod math { pub fn add(a: i32, b: i32) -> i32 { a + b }}
fn main() { let sum = math::add(2, 3); println!("{sum}");}Saída:
5Repare em duas coisas. Primeiro, a função é chamada com math::add(...), usando o nome do módulo como caminho. Segundo, ela está marcada com pub. Sem isso, ninguém fora do módulo conseguiria chamá-la.
Tudo é privado por padrão
Seção intitulada “Tudo é privado por padrão”Vale destacar isto, porque costuma pegar as pessoas de surpresa: o conteúdo de um módulo é privado por padrão. Se você tirar o pub do exemplo acima, o código não compila:
mod math { fn add(a: i32, b: i32) -> i32 { // sem `pub` a + b }}
fn main() { let sum = math::add(2, 3); // ❌ erro: function `add` is private println!("{sum}");}O erro diz que a função add é privada. Tudo o que você quiser deixar disponível para quem está fora do módulo precisa ser marcado com pub, explicitamente. Isso é de propósito: assim o módulo pode esconder suas funções auxiliares internas e expor só as partes que fazem parte da sua API pública.
Módulos aninhados
Seção intitulada “Módulos aninhados”Módulos podem conter outros módulos. É assim que projetos maiores montam uma estrutura em forma de árvore:
mod shapes { pub mod circle { pub fn area(radius: f64) -> f64 { 3.14159 * radius * radius } }}
fn main() { let area = shapes::circle::area(2.0); println!("{area}");}use: encurtando caminhos longos
Seção intitulada “use: encurtando caminhos longos”Escrever shapes::circle::area(...) toda vez cansa. O use traz um caminho para o escopo atual, e aí você pode usá-lo diretamente:
mod shapes { pub mod circle { pub fn area(radius: f64) -> f64 { 3.14159 * radius * radius } }}
use shapes::circle;
fn main() { let area = circle::area(2.0); // mais curto que shapes::circle::area println!("{area}");}Na verdade, você já usou o use antes: é a mesma palavra-chave da página de HashMap (use std::collections::HashMap;).
Dividindo módulos em vários arquivos
Seção intitulada “Dividindo módulos em vários arquivos”Os exemplos acima colocam tudo em um só arquivo, porque o Rust Playground exige isso. Em um projeto de verdade, no seu computador, cada módulo costuma ganhar um arquivo próprio. Um projeto com um módulo math normalmente fica assim:
src/├── main.rs└── math.rsmod math; // diz ao Rust: procure o código deste módulo em math.rs
fn main() { let sum = math::add(2, 3); println!("{sum}");}pub fn add(a: i32, b: i32) -> i32 { a + b}mod math; (com ponto e vírgula e sem corpo) diz ao Rust para carregar o conteúdo do módulo a partir do arquivo math.rs, na mesma pasta. Você vai usar esse padrão assim que um projeto crescer além de um único arquivo.
Prática
Seção intitulada “Prática”1. Um módulo de temperatura
Seção intitulada “1. Um módulo de temperatura”Crie um módulo chamado convert com duas funções públicas: c_to_f (de Celsius para Fahrenheit) e f_to_c (o caminho inverso). No main, imprima 100°C são 212°F e 212°F são 100°C.
Dica: as fórmulas são c * 9.0 / 5.0 + 32.0 e (f - 32.0) * 5.0 / 9.0. Não esqueça o pub, e chame as funções com o nome do módulo, como convert::c_to_f(100.0).
Ver solução
mod convert { pub fn c_to_f(c: f64) -> f64 { c * 9.0 / 5.0 + 32.0 }
pub fn f_to_c(f: f64) -> f64 { (f - 32.0) * 5.0 / 9.0 }}
fn main() { println!("100°C são {}°F", convert::c_to_f(100.0)); println!("212°F são {}°C", convert::f_to_c(212.0));}Saída:
100°C são 212°F212°F são 100°CAs duas funções são pub, então o main (que fica fora do módulo) pode chamá-las. Tire um dos pub e o compilador avisa que aquela função é privada.
2. Uma função auxiliar privada
Seção intitulada “2. Uma função auxiliar privada”Crie um módulo aninhado school::grades com uma função pública letter(score: u32) -> char, que devolve 'A' para 90 ou mais, 'B' para 80 ou mais e 'C' nos outros casos. Dentro de grades, escreva também uma função auxiliar privada is_at_least(score: u32, min: u32) -> bool, que letter usa. Traga school::grades para o escopo com use e imprima a letra (o conceito) de 95, 85 e 70.
Dica: tanto o mod grades de dentro de school quanto o fn letter precisam de pub, mas is_at_least não deve ter. O código dentro do mesmo módulo sempre pode chamar funções privadas.
Ver solução
mod school { pub mod grades { pub fn letter(score: u32) -> char { if is_at_least(score, 90) { 'A' } else if is_at_least(score, 80) { 'B' } else { 'C' } }
// privada: só o código dentro de `grades` pode chamar esta função fn is_at_least(score: u32, min: u32) -> bool { score >= min } }}
use school::grades;
fn main() { for score in [95, 85, 70] { println!("{score} -> {}", grades::letter(score)); }}Saída:
95 -> A85 -> B70 -> Cletter pode chamar is_at_least porque as duas ficam no mesmo módulo. No main, grades::is_at_least(95, 90) falharia com “function is_at_least is private” (a função is_at_least é privada). A ideia é exatamente essa: o módulo mostra uma API pública pequena e guarda as funções auxiliares para si.
mod nome { ... }agrupa código relacionado em um módulo com nome.- Tudo dentro de um módulo é privado por padrão. Coloque
pubpara deixar visível fora do módulo. - O
usetraz um caminho para o escopo, para você não precisar escrevê-lo inteiro toda vez. - Em um projeto com vários arquivos,
mod nome;(sem corpo) carrega o código do módulo a partir do arquivo de mesmo nome. - O código dentro de um módulo sempre pode usar os itens privados desse módulo. Então deixe as funções auxiliares privadas e exponha só o que quem chama precisa.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Por padrão, os itens dentro de um mod são públicos ou privados?
2. Como você diz ao Rust para carregar o código de um módulo a partir de math.rs, em vez de escrevê-lo ali mesmo?
Pontuação: 0 / 2
Para saber mais
Seção intitulada “Para saber mais”- Managing Growing Projects with Packages, Crates, and Modules — The Rust Book (em inglês): o capítulo oficial sobre pacotes, crates e módulos, e como eles se encaixam.
- Defining Modules to Control Scope and Privacy — The Rust Book (em inglês): um exemplo completo de árvore de módulos, com um resumo prático das regras.
- Separating Modules into Different Files — The Rust Book (em inglês): a organização em vários arquivos com mais detalhes, inclusive pastas para módulos aninhados.
- Modules — Rust by Example (em inglês): exemplos executáveis de visibilidade,
use,supereself. - Visibility and privacy — The Rust Reference (em inglês): as regras exatas, inclusive
pub(crate)para “público só dentro do meu crate”.