Por que Rust é a escolha ideal para ferramentas CLI?
\n\nVocê já se perguntou por que todas as ferramentas DevOps modernas — de bat a ripgrep e fd — são escritas em Rust? Não é só por moda. Utilitários CLI em Rust são incrivelmente rápidos, seguros e, o melhor de tudo, podem ser compilados em um único binário minúsculo sem dependências. Nada de "você tem Java instalado?" ou "espere enquanto o Node.js baixa os node_modules". Basta baixar e pronto.
Neste artigo, vamos criar um utilitário CLI em Rust do zero. Não será um "Hello, World!" abstrato, mas uma ferramenta real e útil — um analisador de logs que procura erros, conta a quantidade e exibe os resultados em um formato colorido bonito. E sim, faremos isso em uma noite.
\n\nO que vamos precisar?
\n\nPara começar, o mínimo necessário:
\n- \n
- Rust (instale via
rustup, se ainda não tiver) \n - Qualquer editor de código (VS Code com o plugin rust-analyzer é ideal) \n
- Algumas horas de tempo livre \n
Se você já programou em Python ou Go, Rust pode parecer incomum, mas é lógico. O importante é não ter medo do compilador. Ele não é malvado, ele é apenas cuidadoso.
\n\nPasso 1: Criando o projeto
\n\nAbra o terminal e digite:
\ncargo new log-scanner\ncd log-scanner\n\nCargo é o nosso canivete suíço. Ele criou a estrutura básica com Cargo.toml (arquivo de dependências) e src/main.rs (ponto de entrada). Já podemos executar cargo run e ver "Hello, world!". Mas vamos além.
Abra o Cargo.toml e adicione as dependências que transformarão nosso código em um verdadeiro utilitário CLI em Rust:
[dependencies]\nclap = { version = "4.5", features = ["derive"] }\ncolored = "2.1"\nanyhow = "1.0"\n\n- \n
- clap — análise de argumentos de linha de comando (indispensável) \n
- colored — saída colorida no terminal \n
- anyhow — tratamento conveniente de erros \n
Passo 2: Definindo a estrutura de argumentos
\n\nO mais legal do clap são os macros derive. Você simplesmente descreve a estrutura e a mágica acontece sozinha. Veja como fica:
use clap::Parser;\n\n#[derive(Parser)]\n#[command(name = "log-scanner")]\n#[command(about = "Escaneia arquivos de log e procura por erros")]\nstruct Cli {\n /// Caminho para o arquivo de log\n file: String,\n\n /// String a ser procurada (padrão "ERROR")\n #[arg(short, long, default_value = "ERROR")]\n pattern: String,\n\n /// Mostrar apenas a quantidade de linhas encontradas\n #[arg(short, long)]\n count: bool,\n}\n\nObserve: comentários com três barras /// automaticamente se tornam dicas no --help. Execute cargo run -- --help — e você verá uma ajuda gerada de forma organizada. Esta é uma das razões pelas quais criar CLI em Rust é tão agradável: a documentação se escreve sozinha.
Passo 3: Escrevendo a lógica de busca
\n\nAgora a parte mais interessante — ler o arquivo e procurar correspondências. Rust é famoso por sua manipulação segura de arquivos e memória, mas na prática é simplesmente conveniente:
\n\nuse std::fs::File;\nuse std::io::{BufRead, BufReader};\nuse colored::*;\nuse anyhow::Result;\n\nfn scan_log(file_path: &str, pattern: &str, count_only: bool) -> Result<()> {\n let file = File::open(file_path)?;\n let reader = BufReader::new(file);\n let mut total_matches = 0;\n\n for (line_num, line) in reader.lines().enumerate() {\n let line = line?;\n if line.contains(pattern) {\n total_matches += 1;\n if !count_only {\n println!(\n "{}:{} {}",\n format!("{:>4}", line_num + 1).blue(),\n patt