Nesta aula, vamos dar os primeiros passos práticos com Rust usando o Cargo, o sistema de build e gerenciador de pacotes oficial da linguagem. Você aprenderá a criar um novo projeto, entender a estrutura de diretórios gerada, compilar e executar seu programa, e configurar as dependências básicas no arquivo Cargo.toml. Ao final, você terá um ambiente de desenvolvimento funcional e compreenderá o fluxo de trabalho fundamental com Rust.

O Cargo é uma ferramenta essencial no ecossistema Rust: ele gerencia dependências, compila o código, executa testes, gera documentação e muito mais. Com ele, você não precisa se preocupar com detalhes de compilação manual, pois ele cuida de tudo de forma consistente.

cargo new

O comando cargo new é a maneira mais rápida de iniciar um novo projeto Rust. Ele cria uma estrutura de diretórios padrão com tudo que você precisa para começar a programar. Basta executar no terminal:

cargo new hello_world --bin

O argumento --bin indica que queremos criar um projeto de aplicação binária (executável). Se você omitir, o padrão é --bin mesmo. Para criar uma biblioteca, use --lib. O Cargo também aceita cargo init dentro de um diretório existente para transformá-lo em um projeto Cargo.

Exemplo prático: abra seu terminal, navegue até uma pasta de projetos e execute o comando acima. Você verá uma saída como:

Created binary (application) `hello_world` package

Estrutura do projeto

Após executar cargo new hello_world --bin, o Cargo cria a seguinte estrutura de diretórios e arquivos:

hello_world/
├── Cargo.toml
├── src/
│   └── main.rs
└── .gitignore

Vamos detalhar cada item:

  • Cargo.toml: arquivo de configuração do projeto, no formato TOML (Tom's Obvious, Minimal Language). Ele contém metadados como nome, versão, autores e dependências.
  • src/main.rs: arquivo de código fonte principal. Para projetos binários, o ponto de entrada é a função main.
  • .gitignore: arquivo gerado automaticamente para ignorar a pasta target/ (onde o Cargo coloca os artefatos de compilação) em repositórios Git.

Além disso, quando você compila o projeto, o Cargo cria uma pasta target/ com os binários e arquivos intermediários. Essa estrutura é limpa e organizada, facilitando o gerenciamento de projetos maiores.

cargo run e cargo build

Dois comandos fundamentais do Cargo são cargo build e cargo run. O primeiro compila o projeto sem executá-lo, enquanto o segundo compila e executa imediatamente.

cargo build: Compila o projeto e gera o executável na pasta target/debug/. Por exemplo, após executar cargo build no projeto hello_world, você encontrará o binário em target/debug/hello_world. Use cargo build --release para compilar com otimizações, gerando o binário em target/release/.

cargo run: Compila (se necessário) e executa o binário. É o comando mais usado durante o desenvolvimento, pois agiliza o ciclo de edição-compilação-execução. Exemplo:

cargo run
   Compiling hello_world v0.1.0 (caminho/para/hello_world)
    Finished dev [unoptimized + debuginfo] target(s) in 0.5s
     Running `target/debug/hello_world`
Hello, world!

Você também pode passar argumentos para o programa após --, por exemplo: cargo run -- --arg1 valor.

Cargo.toml básico

O arquivo Cargo.toml é o coração da configuração do projeto. Vamos analisar um exemplo gerado pelo cargo new:

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

[dependencies]

As seções principais são:

  • [package]: contém metadados do pacote. Os campos obrigatórios são name, version e edition. A edition define a versão da linguagem Rust (2015, 2018, 2021, 2024). É recomendado usar a edição mais recente estável (2021).
  • [dependencies]: lista de dependências externas. Cada dependência é especificada no formato nome = "versão". Por exemplo, para adicionar a crate serde, escrevemos serde = "1.0".

Exemplo de um Cargo.toml com dependências:

[package]
name = "meu_projeto"
version = "0.2.0"
authors = ["Seu Nome "]
edition = "2021"

[dependencies]
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }

Além disso, existem seções opcionais como [dev-dependencies] (dependências apenas para testes) e [build-dependencies] (para scripts de build). O Cargo também suporta a especificação de dependências a partir de um repositório Git ou caminho local.

Boas práticas

Sempre mantenha o Cargo.toml organizado e atualizado. Use cargo update para atualizar as dependências conforme as restrições de versão. Prefira usar versões exatas ou com operadores de compatibilidade (como ^ ou ~) para evitar quebras inesperadas. Além disso, é uma boa prática versionar o arquivo Cargo.lock para aplicações, garantindo que todos os desenvolvedores usem as mesmas versões das dependências.

Referências

Exercícios

  1. Crie um novo projeto chamado meu_primeiro_projeto usando cargo new e verifique a estrutura de diretórios gerada. Liste os arquivos e pastas.

    ✓ Resposta: Execute no terminal: cargo new meu_primeiro_projeto --bin. A estrutura será:
    meu_primeiro_projeto/
    ├── Cargo.toml
    ├── src/
    │   └── main.rs
    └── .gitignore
  2. No projeto criado, substitua o conteúdo de src/main.rs para imprimir Olá, Rust! e execute com cargo run. Mostre o código e a saída esperada.

    ✓ Resposta: Código em src/main.rs:
    fn main() {
        println!("Olá, Rust!");
    }
    Saída esperada:
    Olá, Rust!
  3. Adicione uma dependência externa ao projeto: a crate rand na versão 0.8. Edite o Cargo.toml e depois execute cargo build. Mostre como fica o arquivo Cargo.toml após a modificação.

    ✓ Resposta: Adicione no Cargo.toml sob [dependencies]:
    [dependencies]
    rand = "0.8"
    Execute cargo build para baixar e compilar a dependência.
  4. Explique a diferença entre cargo build e cargo build --release. Quando você usaria cada um?

    ✓ Resposta: cargo build compila com configurações de desenvolvimento (sem otimizações, com informações de debug), resultando em compilação rápida e binários maiores. É usado durante o desenvolvimento. cargo build --release compila com otimizações (nível 3), gerando binários menores e mais rápidos, mas a compilação é mais lenta. É usado para versões finais de produção.
  5. O que é o arquivo Cargo.lock? Ele deve ser versionado? Explique.

    ✓ Resposta: O Cargo.lock registra as versões exatas de todas as dependências (incluindo dependências transitivas) usadas na última compilação bem-sucedida. Para aplicações, é recomendado versioná-lo no Git para garantir que todos os desenvolvedores e ambientes de deploy usem as mesmas versões. Para bibliotecas, geralmente não se versiona, pois os usuários dependem do Cargo.toml para especificar versões.