Génériques en Rust : maîtrisez les types comme un pro

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Génériques en Rust : pourquoi sont-ils indispensables ?

\n\n

Quand on débute avec Rust, le système de types peut sembler un adversaire. Le compilateur râle à chaque virgule, et le mot Generic fait trembler. Pourtant, les génériques (types génériques) sont vos meilleurs alliés. Ils vous permettent d'écrire un code flexible, sûr et réutilisable sans sacrifier les performances.

\n\n

Dans cet article, nous allons voir ce que sont les génériques en Rust, comment les utiliser dans les fonctions, les structures et les traits. Vous découvrirez que la programmation générique n'est pas de la magie, mais un outil puissant qui rend votre code plus propre et plus rapide.

\n\n

Que sont les génériques et pourquoi les utiliser ?

\n\n

Imaginez que vous écrivez une fonction qui trouve l'élément maximum dans un tableau. Sans génériques, vous devriez écrire une implémentation séparée pour i32, f64, String, etc. C'est long, fastidieux et viole le principe DRY (Don't Repeat Yourself).

\n\n

Les génériques résolvent ce problème. Ils permettent de paramétrer les types : vous écrivez une seule fonction qui fonctionne avec n'importe quel type de données. Le compilateur génère lui-même les versions de code nécessaires pour chaque cas spécifique. Ce processus s'appelle la monomorphisation.

\n\n

Syntaxe des génériques : du simple au complexe

\n\n

1. Fonctions génériques

\n\n

Commençons par un exemple de base. Supposons que nous voulions créer une fonction qui retourne la valeur passée (fonction identité) :

\n\n
fn identity<T>(value: T) -> T {\n    value\n}\n\nfn main() {\n    let n = identity(42);\n    let s = identity("hello");\n    println!("{}, {}", n, s); // 42, hello\n}
\n\n

Ici, <T> est un paramètre de type. T peut être n'importe quel type : nombre, chaîne, structure. Lors de l'appel, le compilateur déduit automatiquement le type à utiliser. Cela ne fonctionne pas grâce à la répartition dynamique (comme en Java ou Python), mais grâce à la génération de code spécialisé à la compilation. C'est pourquoi Rust ne sacrifie pas les performances.

\n\n

2. Contraintes de type (Trait Bounds)

\n\n

Mais que faire si nous voulons non seulement passer une valeur, mais aussi, par exemple, comparer deux nombres ? Un simple <T> ne suffit pas, car l'opération de comparaison n'est pas définie pour tous les types. Nous devons spécifier que T doit implémenter le trait PartialOrd :

\n\n
fn max<T: PartialOrd>(a: T, b: T) -> T {\n    if a > b { a } else { b }\n}\n\nfn main() {\n    println!("{}", max(10, 20));        // 20\n    println!("{}", max(3.14, 2.71));    // 3.14\n}
\n\n

La notation T: PartialOrd est une trait bound. Elle indique au compilateur : « N'utilise que les types pour lesquels un ordre de comparaison est défini ». Essayez de passer deux chaînes à max — cela fonctionnera, car String implémente aussi PartialOrd. En revanche, si vous passez une structure sans implémentation, vous obtiendrez une erreur de compilation.

\n\n

3. Contraintes multiples

\n\n

Parfois, un type doit satisfaire plusieurs traits à la fois. Par exemple, être à la fois comparable et clonable :

\n\n
fn clone_and_max<T: PartialOrd + Clone>(a: T, b: T) -> T {\n    let a_cloned = a.clone();\n    let b_cloned = b.clone();\n    if a_cloned > b_cloned { a } else { b }\n}
\n\n

La syntaxe T: PartialOrd + Clone signifie que le type doit implémenter les deux traits. C'est puissant, mais à utiliser avec modération : trop de contraintes nuisent à la lisibilité.

\n\n

Génériques dans les structures et les énumérations

\n\n

Structures génériques

\n\n

Les génériques fonctionnent aussi très bien avec les types personnalisés. L'exemple classique est la structure Point, qui peut stocker des coordonnées de n'importe quel type :

\n\n
struct Point<T> {\n    x: T,\n    y: T,\n}\n\nimpl<T> Point<T> {\n    fn new(x:

Blogs

Book Recommendations