Skip to content
Learni
Voir tous les tutoriels
Développement Système

Comment créer une application CLI performante en Rust en 2026

18 minINTERMEDIATE
Read in English

Introduction

Rust est devenu le langage de référence pour les outils en ligne de commande grâce à sa sécurité mémoire et ses performances. Dans ce tutoriel intermédiaire, nous allons construire une CLI qui analyse des fichiers texte et génère des statistiques. Vous apprendrez à structurer un projet, gérer les arguments avec clap, implémenter une logique métier robuste et écrire des tests. Ce guide vous permettra de produire du code prêt pour la production.

Prérequis

  • Rust 1.75+ et Cargo installés
  • Connaissances de base en ownership et traits
  • Terminal et éditeur de code (VS Code recommandé)

Initialisation du projet

terminal
cargo new text-stats --bin
cd text-stats
cargo add clap --features derive

Nous initialisons un projet binaire et ajoutons clap pour le parsing d'arguments. Cela pose les fondations d'une CLI structurée et maintenable.

Définition des arguments

src/main.rs
use clap::Parser;

#[derive(Parser)]
#[command(name = "text-stats")]
struct Args {
    #[arg(short, long)]
    file: String,
}

fn main() {
    let args = Args::parse();
    println!("Analyse du fichier : {}", args.file);
}

Le derive macro de clap génère automatiquement le parsing. Cela évite le code boilerplate et rend les arguments type-safe.

Lecture et analyse du fichier

src/stats.rs
use std::fs;

pub fn analyze_file(path: &str) -> Result<(usize, usize), Box<dyn std::error::Error>> {
    let content = fs::read_to_string(path)?;
    let word_count = content.split_whitespace().count();
    let char_count = content.chars().count();
    Ok((word_count, char_count))
}

Cette fonction lit le fichier et calcule les statistiques. L'utilisation de Result permet une gestion propre des erreurs d'E/S.

Intégration dans main

src/main.rs
use clap::Parser;
mod stats;

#[derive(Parser)]
#[command(name = "text-stats")]
struct Args {
    #[arg(short, long)]
    file: String,
}

fn main() {
    let args = Args::parse();
    match stats::analyze_file(&args.file) {
        Ok((words, chars)) => println!("Mots: {}, Caractères: {}", words, chars),
        Err(e) => eprintln!("Erreur: {}", e),
    }
}

Nous connectons le parsing des arguments à la logique d'analyse. Le pattern match garantit que toutes les erreurs sont traitées explicitement.

Ajout des tests unitaires

src/stats.rs
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_analyze_empty() {
        let result = analyze_file("tests/empty.txt");
        assert!(result.is_ok());
    }
}

Les tests sont placés dans le même fichier pour une meilleure lisibilité. Ils vérifient le comportement sur des cas limites comme un fichier vide.

Bonnes pratiques

  • Utilisez toujours Result pour les opérations faillibles
  • Structurez votre code en modules dès que possible
  • Ajoutez des tests pour chaque fonction publique
  • Préférez les erreurs custom avec thiserror pour les projets plus gros

Erreurs courantes à éviter

  • Ignorer les erreurs avec unwrap() en production
  • Oublier de déclarer les modules avec mod
  • Ne pas gérer les cas de fichiers inexistants
  • Utiliser des chaînes brutes au lieu de types forts pour les chemins

Pour aller plus loin

Découvrez nos formations avancées sur Rust et les architectures logicielles : https://learni-group.com/formations