Cours de programmation séquentielle

Méthodes

Orestis Malaspinas

Méthodes

Généralités

  • Les méthodes sont similaires aux fonctions:
    • Elles sont déclarées avec le mot clé fn.
    • Elles prennent des paramètres d’entrée et ont une valeur de retour.
    • Elles contiennent du code qui est exécuté lorsqu’elles sont appelées quelque part dans le code.
  • Les méthodes sont différentes des fonction:
    • Elles ne sont définies que dans le cadre d’une Struct (ou d’un Enum ou d’un trait object).
    • Leur premier paramètre est toujours self qui est une instance de la structure sur laquelle la méthode est appelée.

Définition d’une méthode (struct)

Le mot-clé self (1/2)


#[derive(Debug)]
struct Rectangle {
    width: usize,
    height: usize,
}

impl Rectangle { // les méthodes de Rectangle se trouvent dans un bloc impl
    // on définit la méthode area qui prend une référence vers une instance d'un Rectangle
    fn area(&self) -> usize { 
        self.width * self.height
    }
}

fn main() {
    let rect = Rectangle {width: 10, height: 5};

    println!("La surface d'un {:?} est donnée par {}", rect, rect.area());
}
  • La méthode area est appelée avec la syntaxe rect.area().
  • Ici &self se réfère immutablement à l’instance rect.
  • Si area prenait d’autres paramètres ils iraient entre les parenthèses.

  • Question: que se passerait-il si on enlevait le & de la définition de area?

Le mot-clé self (2/2)


#[derive(Debug)]
struct Rectangle {
    width: usize,
    height: usize,
}

impl Rectangle { // les méthodes de Rectangle se trouvent dans un bloc impl
    // on définit la méthode set_width qui prend une référence vers self, et une largeur
    fn set_width(&mut self, width: usize) { 
        self.width = width;
    }
}

fn main() {
    let mut rect = Rectangle {width: 10, height: 5}; // rect doit être mutable
    rect.set_width(1_000_000);                       // pour que cette ligne compile

    println!("On a modifié width. L'instance de rectanle est {:?}.", rect);
}
  • La méthode set_width est appelée avec la syntaxe rect.set_width(1_000_000).
  • Ici &mut self se réfère à l’instance rect et est mutable.
  • Si area prenait d’autres paramètres ils iraient entre les parenthèses.

  • Question: que se passerait-il si on enlevait le & de la définition de set_width?

Utilité des méthodes

  • Permet d’organiser le code: toutes les méthodes de la struct Rectangle ne sont visible que via ses instances.
  • Permet de mieux raisonner sur le code.
  • Permet d’encapsuler des fonctions:
    • Certaines méthodes peuvent ne pas être accessibles à l’utilisateur de l’instance d’une structure (pub).
  • Permet d’éviter de taper le type de self dans chaque signature de fonctions.

Définition d’une méthode (enum)

Généralités

  • Comme pour un struct on définit une méthode dans un bloc impl.
  • Comme pour un struct on le premier paramètre d’une méthode est self.

Exemple: Implémentation de is_some


enum Option<T> {
    None,
    Some(T),
}

impl<T> Option <T> {
    // teste si l'option est Some     
    pub fn is_some(&self) -> bool {
        match *self { // on déréférence pour faire le match
            Some(_) => true,
            None => false,
        }
    }
}

Fonctions associées

Généralités

  • On peut également définir des fonction dans des blocs impl qui n’ont pas self en paramètre: les fonctions associées:
    • Exemples: Vec::new(), String::from("texte"), …
  • Appel avec la syntaxe ::.
  • Principalement utilisées pour construire des instances de struct.

Exemple


#[derive(Debug)]
struct Rectangle {
    width: usize,
    height: usize,
}

impl Rectangle { // les fonctions associées se trouvent dans un bloc impl
    fn default() -> Rectangle { 
        Rectangle{ width: 10, height: 100 }
    }

    fn square(side: usize) -> Self { // Self se réfère au type du bloc impl
        Rectangle{ width: side, height: side}
    }

    // on peut rajouter autant de méthodes qu'on veut dans le bloc.
}

fn main() {
    let rect_def = Rectangle::default();
    let square = Rectangle::square(10);

    println!("Un rectangle par défaut: {:?}.", rect_def);
    println!("Un carré est un rectangle particulier: {:?}.", square);
}