Cours de programmation séquentielle

Types génériques

Orestis Malaspinas

Types génériques

Généralités

  • Les types génériques sont utilisés dans des fonctions, structs, enums, …
  • Permettent d’utiliser différents types concrets.
  • Permettent de réduire drastiquement la quantité de code à écrire et de généraliser les concepts.

Exemple (1/2)


fn max_i32(a: i32, b: i32) -> i32 {
    if a > b { a } else { b }
}

fn max_f64(a: f64, b: f64) -> f64 {
    if a > b { a } else { b }
}

fn main() {
    let a = 1;
    let b = 7;

    println!("De {} et {}, {} est le plus grand.", a, b, max_i32(a,b));

    let a = 1.5;
    let b = 7.5;

    println!("De {} et {}, {} est le plus grand.", a, b, max_f64(a,b));
}

Exemple (2/2)


// Cette fonction ne peut pas foncitnner pour tous les types
fn max<T: PartialOrd>(a: T, b: T) -> T {
    if a > b { a } else { b } // si on peut pas comparer a et b
}                             // cela ne peut pas compiler, d'où
                              // le PartialOrd
fn main() {
    let a = 1;
    let b = 7;

    println!("De {} et {}, {} est le plus grand.", a, b, max(a,b));

    let a = 1.5;
    let b = 7.5;

    println!("De {} et {}, {} est le plus grand.", a, b, max(a,b));
}

Dans les struct

Un seul type générique


// Generic point
#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let int_point = Point{ x: 1, y: 2};     // i32 point
    let flt_point = Point{ x: 2.3, y: 4.7}; // f64 point
    // let does_not_work_point = Point{ x: 1, y: 1.5}
}

Deux types génériques


// Generic point
#[derive(Debug)]
struct Point<T, U> {
    x: T,
    y: U,
}

fn main() {
    let int_point = Point{ x: 1, y: 2};     // i32 point
    let flt_point = Point{ x: 2.3, y: 4.7}; // f64 point
    let does_work_now_point = Point{ x: 1, y: 1.5}; // i32, f64 point
}

Dans les méthodes

Exemples


struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn get_x(&self) -> &T {
        &self.x
    }
}

impl Point<f64> {
    fn dist(&self) -> f64 {
        (self.x*self.x + self.y*self.y).sqrt()
    }
}

fn main() {
    let point = Point{ x: 1, y: 2};
    println!("x = {}", point.get_x());
    let point = Point{ x: 1.0, y: 2.0};
    println!("distance = {} et x = {}", point.dist(), point.get_x());
}

Dans les enums

L’Option<T>


// Permet d'avoir un type générique dans Some
enum Some<T> {
    Some(T),
    None,
}

fn main() {
    let int_opt = Some(4);
    let char_opt = Some('a');
}

Considérations philosophiques

Que fait le compilateur?

  • A la compilation le type générique est remplacé par un type spécifique: monomorphisation.
  • Pour chaque type, le compilateur crée une version de la fonction, struct, …
  • Et remplace la fonction générale par le code spécialisé.
  • Aucun coût à l’exécution.