L'une des fonctionnalités les plus puissantes de Rust est le pattern matching, réalisé via l'instruction match. Avec la sortie de Rust 1.26, le terme "match ergonomics" a émergé — une nouvelle logique de déballage et de déréférencement automatique des valeurs de référence à l'intérieur des expressions match, destinée à réduire le nombre de ref et * explicites dans les patterns.
Avant l'introduction des match ergonomics, lors de l'utilisation d'enums enveloppant une valeur dans une référence (par exemple, Option<&T>), il était nécessaire d'indiquer explicitement le déréférencement du pattern :
let opt: Option<&i32> = Some(&10); match opt { Some(&val) => { /* ... */ }, None => {}, }
Ce qui diminuait la lisibilité et augmentait les chances de se tromper avec les niveaux de déréférencement dans des structures complexes.
Avec l'introduction des match ergonomics, Rust déréférencera automatiquement les références dans les patterns, permettant d'écrire un code plus simple et naturel :
let opt: Option<&i32> = Some(&10); match opt { Some(val) => println!("{}", val), None => (), }
Le compilateur "comprend" qu'il doit déréférencer &i32 en i32 pour le confort du programmeur. Cette fonctionnalité facilite considérablement le travail avec les types Option, Result et leurs combinaisons avec des références.
Caractéristiques clés :
* et ref explicites dans les patternsQuelle est la différence entre l'utilisation de ref dans le pattern et une référence à une valeur (par exemple, ref val vs &val) ?
ref crée une référence à une valeur qui se trouve sur la pile, tandis que &val correspond à une référence déjà existante. Cela est crucial, par exemple, si vous avez besoin d'une référence supplémentaire pour travailler avec la mutabilité.
Exemple :
let x = 5; match x { ref r => println!("ref: {}", r), // r: &i32 }
Que se passe-t-il si, lors du pattern matching dans Option<&T>, vous utilisez une référence mutable ?
Le déréférencement automatique fonctionne également avec les références mutables. Si vous avez Option<&mut T>, vous pouvez obtenir une variable mutable directement via le match.
Exemple :
let mut x = 5; let opt = Some(&mut x); match opt { Some(val) => *val += 1, None => {} }
Est-ce que les match ergonomics peuvent entraîner des emprunts non évidents ou des erreurs de possession ?
Oui, si l'on n'est pas conscient qu'un emprunt temporaire (borrow) est créé à l'intérieur du match, ce qui s'applique à toute la branche du matching et peut bloquer d'autres opérations sur cette valeur.
* et ref superflus, ignorant les match ergonomics, ce qui réduit la concision et la clarté du codeUn débutant continue d'utiliser l'ancien style Some(&val) ou Some(ref val), obtenant une erreur ou un comportement imprévisible lors de la mise à jour de Rust vers une nouvelle version
Avantages : Le code fonctionne dans les anciennes versions de Rust et est compréhensible pour ceux qui ont appris avant l'apparition des match ergonomics
Inconvénients : Faible expressivité, risque d'erreurs après les mises à jour du compilateur
Un programmeur utilise les match ergonomics modernes, le code est compact et utilise efficacement le déréférencement automatique
Avantages : Concision, lisibilité claire, moins de risque de se tromper avec les niveaux de références
Inconvénients : Pour les anciennes versions de Rust, un tel code ne conviendra pas et peut causer des incompréhensions chez ceux qui ont peu travaillé avec les idiomes modernes