Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Fonctions et robustesse des signatures

En Rust, les fonctions ne se contentent pas d’exécuter du code : leur signature constitue un contrat statique. Le compilateur sur cette signature pour garantir la sécurité mémoire.

Déclaration et syntaxe de base

Nous déclarons une fonction avec le mot-clé fn.

L’inférence de type ne s’applique pas aux signatures de fonctions. Nous devons indiquer le type de chaque paramètre ainsi que le type du retour.

fn ajouter(a: i32, b: i32) -> i32 {
    a + b // Expression de retour (pas de point-virgule)
}
  • Paramètres : nom: Type.
  • Retour : Indiqué par la flèche ->. Si aucun type n’est spécifié, la fonction retourne le type unité ().
  • Expression vs Déclaration : La dernière ligne sans point-virgule est une expression dont la valeur est retournée. Utiliser return explicitement n’est nécessaire que pour les sorties anticipées.

Robustesse et sémantique de mouvement (move)

La signature d’une fonction indique immédiatement comment les données vont être manipulées vis-à-vis de la propriété (ownership).

Passage par valeur (Transfert de propriété)

Si nous passons un type qui n’implémente pas le trait Copy par valeur, la fonction prend possession de la donnée. La variable d’origine devient inutilisable après l’appel.

fn consommer_texte(s: String) {
    println!("Je possède maintenant : {s}");
}

fn main() {
    let message = String::from("Bonjour");
    consommer_texte(message);
    // println!("{message}"); // ERREUR de compilation : borrow of moved value
}

Passage par référence (Emprunt)

Pour éviter de transférer la propriété, on utilise des références. La signature exprime clairement les intentions d’accès :

// Emprunt immuable : lecture seule, plusieurs lecteurs simultanés possibles
fn afficher_longueur(s: &String) {
    println!("Longueur : {}", s.len());
}

// Emprunt mutable : modification autorisée, exclusivité garantie
fn modifier_texte(s: &mut String) {
    s.push_str(" modifié");
}

Les fonctions qui ne retournent jamais (!)

Il existe des fonctions dont le type de retour est le type never (!). Elles indiquent au compilateur (et au développeur) que le programme va s’arrêter ou diverger à cet endroit (par exemple via un panic!, une boucle infinie ou une sortie de processus).

fn arreter_programme() -> ! {
    panic!("Erreur critique irrécupérable");
}

Robustesse : Exprimer l’absence et l’échec

Une signature robuste en Rust n’utilise pas null ou des codes d’erreur magiques (comme -1). Elle encapsule les résultats dans des types algébriques de données :

  • Option<T> quand une fonction peut ne pas retourner de valeur.
  • Result<T, E> quand une opération peut échouer.
fn diviser(numerateur: f64, denominateur: f64) -> Result<f64, String> {
    if denominateur == 0.0 {
        Err(String::from("Division par zéro impossible"))
    } else {
        Ok(numerateur / denominateur)
    }
}

La signature force l’appelant à gérer explicitement le succès ou l’échec, rendant les flux d’exécution hautement prévisibles et robustes.