Argumentos de la línea de órdenes en Rust con clap

En Rust los argumentos se pueden leer a mano con std::env::args, pero en cuanto hay más de uno conviene clap, que es el crate dominante. Se declara una estructura con los argumentos que admite el programa y clap se encarga de analizarlos, validarlos y generar la ayuda solo.

La dependencia

cargo add clap --features derive
[dependencies]
clap = { version = "4.6.7", features = ["derive"] }

Declarar los argumentos

Cada campo de la estructura es un argumento. Los comentarios que empiezan por tres barras no son comentarios normales: clap los usa como descripción en la ayuda.

use clap::Parser;

#[derive(Parser)]
#[command(version, about = "Saluda a alguien varias veces")]
struct Args {
    /// A quién saludar
    #[arg(short, long)]
    nombre: String,

    /// Cuántas veces
    #[arg(short, long, default_value_t = 1)]
    veces: u8,

    /// Saludar en mayúsculas
    #[arg(long)]
    gritar: bool,
}

fn main() {
    let args = Args::parse();
    for _ in 0..args.veces {
        let saludo = format!("Hola, {}", args.nombre);
        println!("{}", if args.gritar { saludo.to_uppercase() } else { saludo });
    }
}
cargo run -- --nombre Ada --veces 2Hola, Ada
Hola, Ada
cargo run -- -n Grace --gritarHOLA, GRACE

Fíjate en los tipos. nombre: String es obligatorio porque no tiene valor por defecto; veces: u8 lo tiene, así que es opcional; y gritar: bool se convierte en una bandera que está o no está. No hay que escribir ninguna validación: clap deduce todo eso del tipo.

La ayuda la escribe clap

Sin añadir una línea más, el programa ya responde a --help y a --version:

cargo run -- --helpSaluda a alguien varias veces

Usage: saludo [OPTIONS] --nombre <NOMBRE>

Options:
  -n, --nombre <NOMBRE>  A quién saludar
  -v, --veces <VECES>    Cuántas veces [default: 1]
      --gritar           Saludar en mayúsculas
  -h, --help             Print help
  -V, --version          Print version

Y si falta un argumento obligatorio, el error también viene hecho, con el código de salida correcto para un script:

cargo runerror: the following required arguments were not provided:
  --nombre <NOMBRE>

Usage: saludo --nombre <NOMBRE>

For more information, try '--help'.

Lo que se usa a diario

Qué quieres Cómo
Nombre corto y largo #[arg(short, long)]
Valor por defecto #[arg(default_value_t = 1)]
Una bandera sin valor un campo bool
Argumento opcional un campo Option<T>
Se puede repetir un campo Vec<T>
Sin guiones, por posición omitir short y long
Subórdenes tipo git commit #[derive(Subcommand)] en un enum
Por qué un enum para las subórdenes. Si tu herramienta tiene varios modos, cada uno con sus propios argumentos, se modelan como las variantes de un enum: es exactamente el caso de «esto o lo otro, nunca los dos» de la lección de structs y enums. clap se apoya en eso para que no puedas leer los argumentos de una suborden que no se usó.
Si olvidas la característica derive. Igual que con serde, clap sin features = ["derive"] no trae el atributo #[derive(Parser)] y el programa no compila. Añádelo siempre con cargo add clap --features derive en vez de escribir la línea a mano.

El código de esta página se compiló y ejecutó con rustc 1.96.1 y clap 4.6.7 antes de publicarla; las salidas, incluida la ayuda, están copiadas de la ejecución real. Documentación oficial: clap en docs.rs.