Hello World e a estrutura de um projeto Rust

1. O clássico "Hello, World!" em Rust

Toda jornada em uma nova linguagem de programação começa com o tradicional "Hello, World!". Em Rust, esse ritual não poderia ser mais direto. Crie um arquivo chamado main.rs e insira o seguinte código:

fn main() {
    println!("Hello, world!");
}

Vamos analisar cada parte desse pequeno programa:

  • fn main() — Esta é a função principal de todo programa Rust. Ela é o ponto de entrada obrigatório e não recebe parâmetros (por enquanto). O corpo da função é delimitado por chaves {}.

  • println! — Repare no ponto de exclamação. Isso indica que println é uma macro, não uma função comum. Macros em Rust são mais poderosas que funções: elas podem receber um número variável de argumentos e realizar transformações no código em tempo de compilação. A macro println! imprime texto formatado no terminal, adicionando automaticamente uma quebra de linha ao final.

A diferença entre macro e função é sutil mas importante. Enquanto funções são chamadas com nome() (sem exclamação), macros usam nome!(). Rust fornece diversas macros úteis como println!, format!, vec! e panic!.

2. Compilando e executando manualmente

Rust pode ser compilado diretamente usando o compilador rustc. No terminal, navegue até o diretório onde salvou main.rs e execute:

rustc main.rs

Isso gera um binário executável (no Linux/macOS chamado main, no Windows main.exe). Execute-o:

./main

A saída será:

Hello, world!

Embora funcione para programas pequenos, compilar manualmente com rustc tem limitações severas:

  • Não gerencia dependências externas
  • Não oferece perfis de build otimizados
  • Fica impraticável para projetos com múltiplos arquivos

Para projetos reais, utilizamos o Cargo, o gerenciador de projetos e pacotes do Rust.

3. Iniciando um projeto com Cargo

Cargo é uma ferramenta essencial no ecossistema Rust. Para criar um novo projeto, use:

cargo new meu_projeto

Isso gera a seguinte estrutura:

meu_projeto/
├── Cargo.toml
└── src/
    └── main.rs

O arquivo Cargo.toml

Este é o manifesto do projeto, escrito em formato TOML. Contém metadados e declarações de dependências:

[package]
name = "meu_projeto"
version = "0.1.0"
edition = "2021"

[dependencies]
  • [package] — Define o nome, versão e edição da linguagem (atualmente 2021 é a edição padrão).
  • [dependencies] — Aqui listamos as bibliotecas externas (crates) que o projeto utiliza.

O diretório src/

Todo código fonte fica dentro de src/. O arquivo main.rs é o ponto de entrada padrão. O Cargo espera encontrar este arquivo para saber onde começar a execução.

4. Estrutura de diretórios de um projeto Rust

Ao usar Cargo, seu projeto ganha uma estrutura padronizada:

meu_projeto/
├── Cargo.lock
├── Cargo.toml
├── src/
│   └── main.rs
└── target/
    ├── debug/
    └── release/
  • src/ — Todo código fonte do seu projeto. Subdiretórios podem ser criados para organizar módulos.

  • target/ — Contém os artefatos de compilação. É gerado automaticamente pelo Cargo e não deve ser versionado (inclua no .gitignore).

  • Cargo.lock — Arquivo gerado automaticamente que registra as versões exatas de todas as dependências. Garante que todos os desenvolvedores usem as mesmas versões. Para bibliotecas, geralmente não se versiona; para aplicativos, é recomendado manter no repositório.

5. Compilando e executando com Cargo

O Cargo oferece três comandos principais para trabalhar com seu código:

cargo build

Compila o projeto e gera o binário em target/debug/:

cargo build

cargo run

Compila (se necessário) e executa o binário em um único comando:

cargo run

Saída:

Hello, world!

cargo check

Verifica se o código compila sem erros, sem gerar o binário final. É muito mais rápido que cargo build e ideal para uso durante o desenvolvimento:

cargo check

Use cargo check frequentemente enquanto escreve código. Ele detecta erros de tipo, empréstimos inválidos e outros problemas do compilador Rust sem o custo de gerar o executável completo.

6. Perfis de build: debug vs release

O Cargo possui dois perfis principais de compilação:

Perfil debug (padrão)

  • Compilação rápida
  • Sem otimizações de performance
  • Inclui informações de depuração (debug symbols)
  • Binário gerado em target/debug/

Use durante o desenvolvimento para ciclos rápidos de compilação e teste.

Perfil release

  • Otimizações agressivas para performance
  • Compilação mais lenta
  • Remove símbolos de depuração
  • Binário gerado em target/release/

Para compilar em modo release:

cargo build --release

O binário resultante estará em target/release/meu_projeto. Para programas que exigem máxima performance (como jogos ou servidores), sempre compile com --release para distribuição.

7. Boas práticas no projeto inicial

Mantendo um único main.rs

Para programas pequenos e tutoriais, manter tudo em main.rs é perfeitamente aceitável. Conforme o projeto cresce, organize o código em módulos.

Organizando com módulos

Rust usa a palavra-chave mod para declarar módulos. Exemplo básico:

// src/main.rs
mod saudacao;

fn main() {
    saudacao::dizer_ola();
}
// src/saudacao.rs
pub fn dizer_ola() {
    println!("Olá do módulo saudação!");
}

Versionamento com git

Ao iniciar um projeto com cargo new, o Cargo já inicializa um repositório git (a menos que use a flag --vcs none). O arquivo .gitignore gerado automaticamente ignora o diretório target/, pois ele contém apenas artefatos de compilação que podem ser recriados a qualquer momento.

Nunca versionne target/. Sempre inclua no .gitignore:

/target

Conclusão

Dominar a estrutura básica de um projeto Rust e o fluxo de trabalho com Cargo é fundamental antes de mergulhar em conceitos mais avançados como ownership, lifetimes e concorrência. O "Hello, World!" pode parecer simples, mas já revela características importantes da linguagem: a clara separação entre macros e funções, o sistema de módulos e a poderosa ferramenta de build que é o Cargo.

Agora você está pronto para explorar o universo Rust com uma base sólida. Experimente modificar seu main.rs, adicionar novas funções e brincar com a macro println! para formatar diferentes tipos de dados.


Referências