---
title: "Clap Rust: Guia Completo para CLIs em 2026 | Rust Brasil"
url: "https://rustlang.com.br/artigos/clap-vs-structopt/"
markdown_url: "https://rustlang.com.br/artigos/clap-vs-structopt.MD"
description: "Guia completo do Clap 4 em Rust: derive API, subcomandos, validação e auto-completions. Crie CLIs profissionais em Rust."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Clap Rust: Guia Completo para CLIs em 2026 | Rust Brasil

Guia completo do Clap 4 em Rust: derive API, subcomandos, validação e auto-completions. Crie CLIs profissionais em Rust.


## Introdução

Criar aplicações de linha de comando (CLI) é um dos casos de uso mais populares do Rust, e o **Clap** é a biblioteca padrão para parsing de argumentos. Com a versão 4, o Clap consolidou a derive API que torna a criação de CLIs tão simples quanto definir uma struct.

Historicamente, existia o **StructOpt** como uma camada derive separada sobre o Clap. Desde o Clap 3, a derive API foi incorporada diretamente ao Clap, tornando o StructOpt obsoleto. Se você está usando StructOpt, este artigo também serve como guia de migração.

Neste guia, vamos cobrir desde o básico até funcionalidades avançadas como subcomandos, validação customizada, auto-completions e output colorido.

## Dependências no Cargo.toml

```toml
[dependencies]
clap = { version = "4", features = ["derive"] }
```

Para funcionalidades extras:

```toml
[dependencies]
clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] }
clap_complete = "4"    # Auto-completions para shells
anstyle = "1"          # Cores no help
```

## Tabela: Clap 4 vs StructOpt

| Característica | Clap 4 (Derive) | StructOpt |
|---|---|---|
| **Status** | Ativo, versão atual | Deprecado |
| **API** | `#[derive(Parser)]` | `#[derive(StructOpt)]` |
| **Atributo** | `#[arg(...)]` e `#[command(...)]` | `#[structopt(...)]` |
| **Subcomandos** | `#[derive(Subcommand)]` | `#[derive(StructOpt)]` com enum |
| **Validação** | `value_parser` | `validator` |
| **Completions** | `clap_complete` | `structopt::clap::Shell` |
| **Performance** | Otimizada | Overhead adicional |

## CLI Básica

```rust
use clap::Parser;

/// Ferramenta para gerenciar tarefas
#[derive(Parser, Debug)]
#[command(name = "tarefas")]
#[command(version, about, long_about = None)]
struct Cli {
    /// Nome da tarefa a ser criada
    nome: String,

    /// Prioridade da tarefa (1-5)
    #[arg(short, long, default_value_t = 3)]
    prioridade: u8,

    /// Marcar como concluída
    #[arg(short, long)]
    concluida: bool,

    /// Tags da tarefa
    #[arg(short, long)]
    tags: Vec<String>,

    /// Modo verbose
    #[arg(short, long, action = clap::ArgAction::Count)]
    verbose: u8,
}

fn main() {
    let cli = Cli::parse();
    println!("{cli:#?}");

    match cli.verbose {
        0 => println!("Tarefa: {}", cli.nome),
        1 => println!("Tarefa: {} (prioridade: {})", cli.nome, cli.prioridade),
        _ => println!("Tarefa: {:?}", cli),
    }
}
```

Uso:

```bash
$ tarefas "Estudar Rust" --prioridade 5 -t rust -t estudo -v
Tarefa: Estudar Rust (prioridade: 5)
```

Help gerado automaticamente:

```
Ferramenta para gerenciar tarefas

Usage: tarefas [OPTIONS] <NOME>

Arguments:
  <NOME>  Nome da tarefa a ser criada

Options:
  -p, --prioridade <PRIORIDADE>  Prioridade da tarefa (1-5) [default: 3]
  -c, --concluida                Marcar como concluída
  -t, --tags <TAGS>              Tags da tarefa
  -v, --verbose...               Modo verbose
  -h, --help                     Print help
  -V, --version                  Print version
```

## Subcomandos

Subcomandos são definidos como enums com `#[derive(Subcommand)]`:

```rust
use clap::{Parser, Subcommand};
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[command(name = "proj")]
#[command(about = "Gerenciador de projetos Rust")]
struct Cli {
    #[command(subcommand)]
    comando: Comandos,
}

#[derive(Subcommand, Debug)]
enum Comandos {
    /// Criar um novo projeto
    Novo {
        /// Nome do projeto
        nome: String,

        /// Template a usar
        #[arg(short, long, default_value = "basico")]
        template: String,
    },

    /// Compilar o projeto
    Build {
        /// Compilar em modo release
        #[arg(short, long)]
        release: bool,

        /// Diretório de saída
        #[arg(short, long)]
        output: Option<PathBuf>,
    },

    /// Executar testes
    Test {
        /// Filtro de testes
        filtro: Option<String>,

        /// Executar testes ignorados
        #[arg(long)]
        include_ignored: bool,
    },

    /// Publicar no crates.io
    Publish {
        /// Dry run (sem publicar de verdade)
        #[arg(long)]
        dry_run: bool,
    },
}

fn main() {
    let cli = Cli::parse();

    match cli.comando {
        Comandos::Novo { nome, template } => {
            println!("Criando projeto '{nome}' com template '{template}'");
        }
        Comandos::Build { release, output } => {
            let modo = if release { "release" } else { "debug" };
            println!("Compilando em modo {modo}");
            if let Some(path) = output {
                println!("Saída: {}", path.display());
            }
        }
        Comandos::Test { filtro, include_ignored } => {
            println!("Executando testes");
            if let Some(f) = filtro {
                println!("Filtro: {f}");
            }
            if include_ignored {
                println!("Incluindo testes ignorados");
            }
        }
        Comandos::Publish { dry_run } => {
            if dry_run {
                println!("Dry run: verificando publicação...");
            } else {
                println!("Publicando...");
            }
        }
    }
}
```

## Validação de Argumentos

### Validação com value_parser

```rust
use clap::Parser;
use std::path::PathBuf;

#[derive(Parser, Debug)]
struct Cli {
    /// Porta do servidor (1024-65535)
    #[arg(short, long, value_parser = clap::value_parser!(u16).range(1024..=65535))]
    porta: u16,

    /// Arquivo de entrada (deve existir)
    #[arg(short, long, value_parser = validar_arquivo_existe)]
    entrada: PathBuf,

    /// Nível de log
    #[arg(short, long, value_parser = ["debug", "info", "warn", "error"])]
    log_level: String,

    /// Email do usuário
    #[arg(short, long, value_parser = validar_email)]
    email: String,
}

fn validar_arquivo_existe(s: &str) -> Result<PathBuf, String> {
    let path = PathBuf::from(s);
    if path.exists() {
        Ok(path)
    } else {
        Err(format!("Arquivo não encontrado: {s}"))
    }
}

fn validar_email(s: &str) -> Result<String, String> {
    if s.contains('@') && s.contains('.') {
        Ok(s.to_string())
    } else {
        Err(format!("Email inválido: {s}"))
    }
}

fn main() {
    let cli = Cli::parse();
    println!("{cli:#?}");
}
```

### Valores de Enums

```rust
use clap::{Parser, ValueEnum};

#[derive(Debug, Clone, ValueEnum)]
enum Formato {
    Json,
    Yaml,
    Toml,
    Csv,
}

#[derive(Parser, Debug)]
struct Cli {
    /// Formato de saída
    #[arg(short, long, value_enum, default_value_t = Formato::Json)]
    formato: Formato,
}

fn main() {
    let cli = Cli::parse();
    match cli.formato {
        Formato::Json => println!("Saída em JSON"),
        Formato::Yaml => println!("Saída em YAML"),
        Formato::Toml => println!("Saída em TOML"),
        Formato::Csv => println!("Saída em CSV"),
    }
}
```

## Variáveis de Ambiente

```rust
use clap::Parser;

#[derive(Parser, Debug)]
struct Cli {
    /// URL do banco de dados
    #[arg(long, env = "DATABASE_URL")]
    database_url: String,

    /// Token de API
    #[arg(long, env = "API_TOKEN", hide_env_values = true)]
    api_token: String,

    /// Porta do servidor
    #[arg(short, long, env = "PORT", default_value_t = 8080)]
    porta: u16,
}

fn main() {
    let cli = Cli::parse();
    println!("DB: {}", cli.database_url);
    println!("Porta: {}", cli.porta);
}
```

## Auto-Completions para Shells

Gerar scripts de auto-complete para bash, zsh, fish e PowerShell:

```rust
use clap::{Parser, Subcommand};
use clap_complete::{generate, Shell};
use std::io;

#[derive(Parser)]
#[command(name = "minha-cli")]
struct Cli {
    #[command(subcommand)]
    comando: Comandos,
}

#[derive(Subcommand)]
enum Comandos {
    /// Executar a aplicação
    Run,
    /// Gerar completions para o shell
    Completions {
        /// Shell alvo
        #[arg(value_enum)]
        shell: Shell,
    },
}

fn main() {
    let cli = Cli::parse();

    match cli.comando {
        Comandos::Run => {
            println!("Executando...");
        }
        Comandos::Completions { shell } => {
            let mut cmd = <Cli as clap::CommandFactory>::command();
            generate(shell, &mut cmd, "minha-cli", &mut io::stdout());
        }
    }
}
```

Uso:

```bash
# Gerar completions para bash
minha-cli completions bash > /etc/bash_completion.d/minha-cli

# Para zsh
minha-cli completions zsh > ~/.zfunc/_minha-cli

# Para fish
minha-cli completions fish > ~/.config/fish/completions/minha-cli.fish
```

## Output Colorido

Para output colorido no terminal, combine com crates como `colored` ou `owo-colors`:

```toml
[dependencies]
clap = { version = "4", features = ["derive"] }
colored = "2"
indicatif = "0.17"  # Barras de progresso
```

```rust
use clap::Parser;
use colored::Colorize;

#[derive(Parser)]
struct Cli {
    #[command(subcommand)]
    comando: Comando,
}

#[derive(clap::Subcommand)]
enum Comando {
    /// Verificar status do projeto
    Status,
    /// Compilar o projeto
    Build,
}

fn main() {
    let cli = Cli::parse();

    match cli.comando {
        Comando::Status => {
            println!("{} Verificando status...", "●".blue());
            println!("  {} 3 testes passando", "✓".green());
            println!("  {} 1 warning", "!".yellow());
            println!("  {} Nenhum erro", "✓".green());
        }
        Comando::Build => {
            println!("{}", "Compilando projeto...".bold());
            println!("  {} src/main.rs", "Compilando".green().bold());
            println!("  {} Build completo em 2.3s", "Sucesso:".green().bold());
        }
    }
}
```

### Barras de Progresso com indicatif

```rust
use indicatif::{ProgressBar, ProgressStyle};
use std::thread;
use std::time::Duration;

fn main() {
    let pb = ProgressBar::new(100);
    pb.set_style(
        ProgressStyle::with_template(
            "{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})"
        )
        .unwrap()
        .progress_chars("█▓░"),
    );

    for _ in 0..100 {
        pb.inc(1);
        thread::sleep(Duration::from_millis(30));
    }
    pb.finish_with_message("Concluído!");
}
```

## Migração do StructOpt para Clap 4

Se você tem um projeto usando StructOpt, aqui está o guia de migração:

### Dependências

```toml
# Antes (StructOpt)
[dependencies]
structopt = "0.3"

# Depois (Clap 4)
[dependencies]
clap = { version = "4", features = ["derive"] }
```

### Derives e Atributos

```rust
// Antes (StructOpt)
use structopt::StructOpt;

#[derive(StructOpt)]
#[structopt(name = "minha-cli", about = "Descrição")]
struct Cli {
    #[structopt(short, long, default_value = "8080")]
    porta: u16,

    #[structopt(subcommand)]
    cmd: Comando,
}

#[derive(StructOpt)]
enum Comando {
    #[structopt(about = "Executar")]
    Run {
        #[structopt(short, long)]
        verbose: bool,
    },
}

fn main() {
    let cli = Cli::from_args();
}
```

```rust
// Depois (Clap 4)
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = "minha-cli", about = "Descrição")]
struct Cli {
    #[arg(short, long, default_value_t = 8080)]
    porta: u16,

    #[command(subcommand)]
    cmd: Comando,
}

#[derive(Subcommand)]
enum Comando {
    /// Executar
    Run {
        #[arg(short, long)]
        verbose: bool,
    },
}

fn main() {
    let cli = Cli::parse();
}
```

### Principais mudanças na migração:

| StructOpt | Clap 4 |
|---|---|
| `#[derive(StructOpt)]` | `#[derive(Parser)]` ou `#[derive(Subcommand)]` |
| `#[structopt(...)]` | `#[arg(...)]` para args, `#[command(...)]` para command |
| `Cli::from_args()` | `Cli::parse()` |
| `default_value = "8080"` | `default_value_t = 8080` (tipado) |
| `validator = "fn"` | `value_parser = fn` |
| `possible_values` | `value_enum` ou `value_parser` |

## Padrões e Boas Práticas

1. **Use doc comments** (`///`) como descrições — eles aparecem no `--help`
2. **Sempre defina `#[command(version)]`** para que `--version` funcione
3. **Use `value_enum`** para argumentos com valores finitos
4. **Prefira `default_value_t`** sobre `default_value` para tipos não-String
5. **Use `env`** para configurações que também podem vir de variáveis de ambiente
6. **Gere completions** para melhorar a experiência do usuário
7. **Use `hide = true`** para flags internas/de debug

```rust
use clap::Parser;

/// Minha ferramenta incrível para gerenciar deploys
#[derive(Parser)]
#[command(version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
    /// Ambiente alvo
    #[arg(short, long, value_enum)]
    ambiente: Ambiente,

    /// Flags de debug (interno)
    #[arg(long, hide = true)]
    debug_flags: Option<String>,
}

#[derive(Clone, clap::ValueEnum)]
enum Ambiente {
    Dev,
    Staging,
    Producao,
}
```

## Conclusão

O Clap 4 é a ferramenta definitiva para criar CLIs em Rust. A derive API torna o processo declarativo e ergonômico, enquanto features como validação, subcomandos, completions e variáveis de ambiente cobrem praticamente qualquer necessidade. Se você ainda usa StructOpt, a migração para Clap 4 é simples e vale o esforço.

## Veja Também

- [Tutorial: Construindo uma CLI com Clap](/tutoriais/cli-com-clap/)
- [Receita: Ler Argumentos da Linha de Comando](/receitas/ler-argumentos-cli/)
- [Error Handling: anyhow vs thiserror vs miette](/artigos/error-handling-libs/)
- [Tracing vs Log em Rust](/artigos/tracing-vs-log/)
- [Cargo: Ferramentas Essenciais para Produção](/artigos/cargo-ferramentas-essenciais/)

---

Explore como construir CLIs poderosas em outras linguagens:

- <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">CLIs em Go com Cobra: o padrão da indústria para ferramentas de linha de comando</a>
- <a href="https://python.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'python.dev.br' })">CLIs em Python com Click e argparse: interfaces de linha de comando simples e poderosas</a>
