---
title: Cours de programmation séquentielle
subtitle: Méthodes
author: Orestis Malaspinas
sansfont: Sans Serif
---

# Méthodes

## Généralités

- Les **méthodes** sont similaires aux fonctions:
	- Elles sont déclarées avec le mot clé `fn`{.rust}.
	- 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`{.rust} ou d'un `trait object`{.rust}).
	- Leur premier paramètre est **toujours** `self`{.rust} qui est une instance de la structure sur laquelle la méthode est appelée.

# Définition d'une méthode (`struct`{.rust})

## Le mot-clé `self`{.rust} (1/2)

<pre><code data-trim="hljs rust" class="lang-rust">
#[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());
}
</code></pre>

- La méthode `area`{.rust} est appelée avec la syntaxe `rect.area()`{.rust}.
- Ici `&self`{.rust} se réfère **immutablement** à l'instance `rect`{.rust}.
- Si `area`{.rust} prenait d'autres paramètres ils iraient entre les parenthèses.

- Question: que se passerait-il si on enlevait le `&`{.rust} de la définition de `area`{.rust}?

## Le mot-clé `self`{.rust} (2/2)

<pre><code data-trim="hljs rust" class="lang-rust">
#[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);
}
</code></pre>

- La méthode `set_width`{.rust} est appelée avec la syntaxe `rect.set_width(1_000_000)`{.rust}.
- Ici `&mut self`{.rust} se réfère à l'instance `rect`{.rust} et est **mutable**.
- Si `area`{.rust} prenait d'autres paramètres ils iraient entre les parenthèses.

- Question: que se passerait-il si on enlevait le `&`{.rust} de la définition de `set_width`{.rust}?

## 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`{.rust})

## Généralités

- Comme pour un `struct`{.rust} on définit une méthode dans un bloc `impl`{.rust}.
- Comme pour un `struct`{.rust} on le premier paramètre d'une méthode est `self`{.rust}.

## Exemple: Implémentation de `is_some`{.rust}

<pre><code data-trim="hljs rust">
enum Option&lt;T&gt; {
    None,
    Some(T),
}

impl&lt;T&gt; Option &lt;T&gt; {
	// 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,
        }
    }
}
</code></pre>


# Fonctions associées

## Généralités

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

## Exemple

<pre><code data-trim="hljs rust" class="lang-rust">
#[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);
}
</code></pre>