<h2>Introdução ao Clap: Por Que Usar?</h2>
<p>O <code>clap</code> é a crate mais popular do Rust para parsing de argumentos de linha de comando. Diferentemente de fazer parsing manual com <code>std::env::args()</code>, o clap oferece uma API elegante, validação automática, geração de help text e tratamento de erros robusto. Se você está desenvolvendo ferramentas CLI em Rust, o clap é praticamente obrigatório — economiza horas de desenvolvimento e reduz drasticamente bugs relacionados a entrada do usuário.</p>
<p>O clap oferece duas abordagens principais: a API de builder e a API de atributos derive. Vou focar na abordagem derive (mais moderna e recomendada), que usa macros para gerar o parsing automaticamente a partir de structs Rust.</p>
<h2>Instalação e Configuração Básica</h2>
<h3>Setup Inicial</h3>
<p>Comece adicionando o clap ao seu <code>Cargo.toml</code>:</p>
<pre><code class="language-toml">[dependencies]
clap = { version = "4.4", features = ["derive"] }</code></pre>
<p>A feature <code>derive</code> ativa o macro <code>#[derive(Parser)]</code>, essencial para a abordagem que usaremos. Agora, um exemplo funcional bem simples:</p>
<pre><code class="language-rust">use clap::Parser;
#[derive(Parser, Debug)]
#[command(name = "MeuApp")]
#[command(about = "Uma ferramenta CLI demonstrativa", long_about = None)]
struct Args {
/// Nome do arquivo a processar
#[arg(short, long)]
arquivo: String,
/// Modo verboso
#[arg(short, long)]
verbose: bool,
}
fn main() {
let args = Args::parse();
println!("Arquivo: {}", args.arquivo);
println!("Verbose: {}", args.verbose);
}</code></pre>
<p>Execute com <code>cargo run -- --arquivo dados.txt --verbose</code> e veja a mágica acontecer. O clap automaticamente valida se o arquivo foi fornecido, gera mensagens de erro amigáveis e oferece <code>--help</code> sem você escrever uma linha de código para isso.</p>
<h2>Argumentos, Opções e Subcomandos</h2>
<h3>Argumentos vs Opções</h3>
<p>Argumentos posicionais (sem <code>--</code> ou <code>-</code>) e opções (com <code>--</code> ou <code>-</code>) funcionam diferentemente no clap:</p>
<pre><code class="language-rust">use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Argumento posicional obrigatório
#[arg(value_name = "ORIGEM")]
origem: String,
/// Argumento posicional opcional
#[arg(value_name = "DESTINO")]
destino: Option<String>,
/// Opção com valor
#[arg(short = 'o', long = "output")]
output: Option<String>,
/// Flag booleana (presente ou ausente)
#[arg(short, long)]
force: bool,
/// Múltiplos valores
#[arg(short = 'f', long = "filter")]
filtros: Vec<String>,
}
fn main() {
let args = Args::parse();
println!("Origem: {}", args.origem);
if let Some(dest) = args.destino {
println!("Destino: {}", dest);
}
println!("Filtros: {:?}", args.filtros);
}</code></pre>
<p>Execute assim: <code>cargo run -- arquivo.txt dest.txt -f json -f csv --force</code>. O clap coleta múltiplos valores em <code>Vec</code> automaticamente.</p>
<h3>Subcomandos</h3>
<p>Para aplicações complexas, subcomandos são essenciais:</p>
<pre><code class="language-rust">use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "admin")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Criar novo usuário
Create {
#[arg(short, long)]
name: String,
#[arg(short, long)]
email: String,
},
/// Deletar usuário
Delete {
#[arg(short, long)]
id: u32,
},
/// Listar todos os usuários
List {
#[arg(short, long)]
verbose: bool,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Create { name, email } => {
println!("Criando usuário: {} ({})", name, email);
}
Commands::Delete { id } => {
println!("Deletando usuário com ID: {}", id);
}
Commands::List { verbose } => {
println!("Listando usuários (verbose={})", verbose);
}
}
}</code></pre>
<p>Use assim: <code>cargo run -- create --name "João" --email "joao@email.com"</code>. Cada subcomando tem seus próprios argumentos e help text.</p>
<h2>Validação, Valores Padrão e Comportamentos Avançados</h2>
<h3>Validação e Restrições</h3>
<p>O clap oferece várias formas de validar entrada:</p>
<pre><code class="language-rust">use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Número entre 1 e 100
#[arg(short, long, value_parser = clap::value_parser!(u32).range(1..=100))]
numero: u32,
/// Arquivo que deve existir
#[arg(short, long, value_parser = clap::builder::PathBufValueParser::new())]
arquivo: std::path::PathBuf,
/// Valor de um conjunto específico
#[arg(short, long, value_parser = ["json", "yaml", "toml"])]
formato: String,
/// Valor padrão
#[arg(short, long, default_value = "info")]
nivel: String,
}
fn main() {
let args = Args::parse();
println!("Número: {}, Arquivo: {:?}", args.numero, args.arquivo);
println!("Formato: {}, Nível: {}", args.formato, args.nivel);
}</code></pre>
<p>Se executar <code>cargo run -- --numero 150</code>, o clap rejeita e exibe um erro claro. O <code>value_parser</code> faz validação automática.</p>
<h3>Comportamentos Avançados</h3>
<p>Para casos mais complexos, use atributos customizados:</p>
<pre><code class="language-rust">use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Requer que outra flag esteja presente
#[arg(short, long, requires = "token")]
autenticado: bool,
/// Conflita com outra flag
#[arg(long, conflicts_with = "output")]
stdout: bool,
#[arg(long)]
output: Option<String>,
/// Token (obrigatório se 'autenticado' estiver presente)
#[arg(short, long)]
token: Option<String>,
/// Variável de ambiente como fallback
#[arg(short, long, env = "APP_DEBUG")]
debug: bool,
}
fn main() {
let args = Args::parse();
println!("{:?}", args);
}</code></pre>
<p>Experimente: <code>cargo run -- --autenticado</code> (vai falhar porque precisa de <code>--token</code>). Ou <code>cargo run -- --autenticado --token abc123</code> (funciona).</p>
<h2>Conclusão</h2>
<p>Aprendemos que o <strong>clap simplifica drasticamente o desenvolvimento de CLIs em Rust</strong>, eliminando boilerplate e oferecendo validação robusta out-of-the-box. A <strong>abordagem derive é mais legível e manutenível</strong> do que construção manual de parsers. E, finalmente, o clap <strong>escala bem</strong>: de aplicações simples com um único comando até sistemas complexos com múltiplos subcomandos, validações customizadas e comportamentos avançados.</p>
<p>Na prática, 95% dos seus problemas de parsing será resolvido com os conceitos aqui apresentados. O restante está bem documentado na documentação oficial.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://docs.rs/clap/latest/clap/" target="_blank" rel="noopener noreferrer">Documentação oficial do clap</a></li>
<li><a href="https://docs.rs/clap/latest/clap/_derive/index.html" target="_blank" rel="noopener noreferrer">Guia de Derive API do clap</a></li>
<li><a href="https://doc.rust-lang.org/book/ch12-00-an-io-project.html" target="_blank" rel="noopener noreferrer">Rust Book - Building a Command Line Program</a></li>
<li><a href="https://github.com/clap-rs/clap/tree/master/examples" target="_blank" rel="noopener noreferrer">Exemplos completos do clap no GitHub</a></li>
<li><a href="https://rust-cli.github.io/book/" target="_blank" rel="noopener noreferrer">The Rust CLI Book</a></li>
</ul>