Les Génériques en Rust

Introduction aux Génériques

Les génériques en Rust permettent aux développeurs de rédiger un code adaptable et réutilisable capable d'interagir avec différents types de données. Ils sont particulièrement utiles pour créer des fonctions, des structures de données et des méthodes qui peuvent travailler avec une variété de types, tout en maintenant la sécurité de type à la compilation.

Fonction Générique

Pour définir une fonction générique, il suffit d’indiquer un paramètre de type à l’intérieur de crochets angulaires (<>). Ce paramètre peut ensuite être utilisé comme substitut pour n’importe quel type. Par convention, beaucoup de développeurs Rust utilisent la lettre T, qui signifie Type. Voici un exemple de définition d'une fonction générique :

fn ma_fonction(valeur: T) -> T {  ...}

Dans cet exemple, ma_fonction est une fonction générique qui prend un paramètre valeur de n'importe quel type T.

Exemple de Fonction Générique Retournant une Valeur

Considérons un autre exemple d'une fonction générique qui retourne un résultat :

fn tester(a: T) -> T {  return a;}
fn main() {  println!("{}", tester(8));}

La sortie de cet exemple sera :

8

Utilisation d'une Structure de Données Générique

Il est aussi possible de définir des structures (struct) ou des énumérations (enum) avec des génériques. Voici un exemple de définition d'une structure avec des génériques :

struct Coordonnees {  x: T,  y: T,}
fn main() {  let coord_int = Coordonnees {x: 5, y: 4};  let coord_float = Coordonnees {x: 5.01, y: 4.10};  println!("coord_int: ({}, {})", coord_int.x, coord_int.y);  println!("coord_float: ({}, {})", coord_float.x, coord_float.y);}

La sortie de cet exemple sera :

coord_int: (5, 4)
coord_float: (5.01, 4.1)

Gestion de Types Différents

Notez que dans cet exemple, il faut s'assurer que x et y sont du même type, sinon une erreur de types non concordants apparaîtra. Il est également possible de définir une structure avec plusieurs paramètres de type génériques :

struct Coordonnees {  x: T,  y: U,}
fn main() {  let coord_mixte = Coordonnees {x: 10, y: 5.9};  println!("coord_mixte: ({}, {})", coord_mixte.x, coord_mixte.y);}

Cela produira la sortie suivante sans erreur de types :

coord_mixte: (10, 5.9)

Limites de Traits dans les Génériques

Dans Rust, un trait est un ensemble de méthodes qui définissent un comportement. Les limites de traits spécifient qu'un type doit implémenter un trait donné pour être utilisé dans un contexte particulier. Cela contribue à garantir la sécurité de type tout en permettant le polymorphisme et en clarifiant les capacités du type générique, améliorant ainsi la lisibilité du code. Voici un exemple d'une fonction générique qui renvoie la somme de deux entiers en utilisant des limites de traits :

fn somme>(a: T, b: T) -> T {  return a + b;}
fn main() {  println!("La somme de 4 et 5 est {}", somme(4, 5));}

Dans cet exemple, T est limité par std::ops::Add pour garantir que l'opérateur + peut être utilisé. La sortie sera :

La somme de 4 et 5 est 9