diff --git a/methods.md b/methods.md index 3928605a72b46eb8f665cdf96935109a6e43fb10..8f2452316ef2e64af51aa10a7f10acfae0af7ed7 100644 --- a/methods.md +++ b/methods.md @@ -7,5 +7,120 @@ sansfont: Sans Serif # Méthodes -Under construction +## 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 + +## 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. + +# 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> \ No newline at end of file