From 5c12b6522b02c1adb953fc10546891df1f2cdad9 Mon Sep 17 00:00:00 2001 From: Jimskapt Date: Mon, 26 Aug 2019 12:54:49 +0200 Subject: [PATCH 1/4] :twisted_rightwards_arrows: Merging translation of ch04-03 by @Jimskapt From https://github.com/quadrifoglio/rust-book-fr/blob/fr-ch04/second-edition/src/ch04-03-slices.md --- FRENCH/src/SUMMARY.md | 2 + FRENCH/src/ch04-03-slices.md | 961 ++++++++++++++++++++++++++++++++ FRENCH/src/translation-terms.md | 2 + 3 files changed, 965 insertions(+) create mode 100644 FRENCH/src/ch04-03-slices.md diff --git a/FRENCH/src/SUMMARY.md b/FRENCH/src/SUMMARY.md index 2b62457da4..d66c9dd786 100644 --- a/FRENCH/src/SUMMARY.md +++ b/FRENCH/src/SUMMARY.md @@ -13,3 +13,5 @@ - [Hello, Cargo!](ch01-03-hello-cargo.md) - [Programmer un jeu de devinettes](ch02-00-guessing-game-tutorial.md) + +- [Le type Slice](ch04-03-slices.md) diff --git a/FRENCH/src/ch04-03-slices.md b/FRENCH/src/ch04-03-slices.md new file mode 100644 index 0000000000..f617e28a6d --- /dev/null +++ b/FRENCH/src/ch04-03-slices.md @@ -0,0 +1,961 @@ + + +## Le type Slice + + + +Un autre type de données qui n'applique pas le principe d'appartenance est le +*slice*. Un slice vous permet d'avoir une référence vers une suite continue +d'éléments dans une collection plutôt que toute la collection. + + + +Voici un petit problème de programmation : écrire une fonction qui prend une +chaîne de caractères et retourne le premier mot qu'elle trouve dans cette +chaîne. Si la fonction ne trouve pas d'espace dans la chaîne, cela veut dire +que toute la chaîne est un seul mot, donc la chaîne en entier doit être +retournée. + + + +Imaginons la signature de cette fonction : + + + +```rust,ignore +fn first_word(s: &String) -> ? +``` + + + +Cette fonction, `first_word`, prends un `&String` comme paramètre. Nous ne +voulons pas se l'approprier, donc tout va bien. Mais que devons-nous +retourner ? Nous n'avons pas de moyen de désigner une *partie* de chaîne de +caractères. Cependant, nous pouvons retourner l'index de la fin du mot. +Essayons cela dans l'entrée 4-5 : + + + +Nom du fichier : src/main.rs + + + +```rust +fn first_word(s: &String) -> usize { + let bytes = s.as_bytes(); + + for (i, &item) in bytes.iter().enumerate() { + if item == b' ' { + return i; + } + } + + s.len() +} +``` + + + +Entrée 4-5 : la fonction `first_word` qui retourne la +valeur d'index d'octet dans le paramètre `String` + + + +Regardons un peu plus en détail ce code. Puisque nous avons besoin de parcourir +le `String` éléments par éléments et vérifier si leur valeur est un espace, +nous allons convertir notre `String` en tableau d'octets en utilisant la +méthode `as_bytes` : + + + +```rust,ignore +let bytes = s.as_bytes(); +``` + + + +Ensuite, nous créons un itérateur sur le tableau d'octets en utilisant la +méthode `iter` : + + + +```rust,ignore +for (i, &item) in bytes.iter().enumerate() { +``` + + + +Nous discuterons plus en détail des itérateur dans le chapitre 13. Pour le +moment, sachez que ce `iter` est une méthode qui retourne chaque élément dans +une collection, et que `enumerate` enveloppe le résultat de `iter` et retourne +plutôt chaque élément comme une partie d'un tuple. Le premier élément du tuple +retourné est l'index, et le second élément est une référence vers l'élément. +C'est un peu plus pratique que de calculer les index par nous-mêmes. + + + +Comme la méthode `enumerate` retourne un tuple, ne pouvons utiliser une +technique pour décomposer ce tuple, comme nous pourrions le faire n'importe où +avec Rust. Donc dans la boucle `for`, nous précisions un schéma qui indique que +nous définissons `i` pour l'index à partir du tuple et `&item` for chaque octet +dans le tuple. Comme nous obtenons une référence vers l'élément avec +`.iter().enumerate()`, nous utilisons `&` dans le schéma. + + + +Nous recherchons l'octet qui représente l'espace en utilisant la syntaxe des +mots binaires. Si nous trouvons un espace, nous retournons sa position. Sinon, +nous retournons la taille du string en utilisant `s.len()` : + + + +```rust,ignore + if item == b' ' { + return i; + } +} +s.len() +``` + + + +Nous avons maintenant une façon de trouver l'index de la fin du premier mot +dans la chaîne de caractères, mais il y a un problème. Nous retournons un +`usize` seul, mais il n'est important que lorsqu'il est mis en rapport avec +le `&String`. Autrement dit, parce qu'il a une valeur séparée du `String`, il +n'y a pas de garantie qu'il sera toujours valide dans le futur. Imaginons +le programme dans l'entrée 4-6 qui utilise la fonction de l'entrée 4-5 : + + + +Nom du fichier : src/main.rs + + + +```rust +# fn first_word(s: &String) -> usize { +# let bytes = s.as_bytes(); +# +# for (i, &item) in bytes.iter().enumerate() { +# if item == b' ' { +# return i; +# } +# } +# +# s.len() +# } +# +fn main() { + let mut s = String::from("hello world"); + + let word = first_word(&s); // word aura 5 comme valeur. + + s.clear(); // Ceci vide le String, il faut maintenant "". + + // word a toujours la valeur 5 ici, mais il n'y a plus de chaîne qui donne + // du sens à la valeur 5. word est maintenant complètement invalide ! +} +``` + + + +Entrée 4-6 : On stocke le résultat de l'appel à la +fonction `first_word` et ensuite on change le contenu du `String` + + + +Ce programme se compile sans aucune erreur et serait toujours OK si nous +utilisions `word` après avoir appelé `s.clear()`. `word` n'est pas du tout lié +à l'état de `s`, donc `word` contient toujours la valeur `5`. Nous pourrions +utiliser cette valeur `5` avec la variable `s` pour essayer d'en extraire le +premier mot, mais cela serait un bogue, car le contenu de `s` a changé depuis +que nous avons enregistré `5` dans `word`. + + + +Se préoccuper en permanence que l'index dans `word` ne soit plus synchronisé +avec les données dans `s` est fastidieux et source d'erreur ! La gestion de ces +index est encore plus risquée si nous écrivons une fonction second_word. Sa +signature ressemblerait à quelque chose comme ceci : + + + +```rust,ignore +fn second_word(s: &String) -> (usize, usize) { +``` + + + +Maintenant nous gérons un index de début *et* un index de fin, et nous avons +encore plus de valeurs qui sont calculées à partir de la donnée dans un +état particulier, mais qui n'est pas lié à son état en temps réel. Nous avons +maintenant trois variables isolées qui ont besoin d'être maintenu à jour. + + + +Heureusement, Rust a une solution pour ce problème : les slices de chaînes de +caractères. + + + +### Les slices de chaînes de caractères + + + +Un *slice de chaîne de caractère* est une référence à une partie d'un `String`, +et ressemble à ceci : + + + +```rust +let s = String::from("hello world"); + +let hello = &s[0..5]; +let world = &s[6..11]; +``` + + + +Ce serait comme prendre une référence pour tout le `String`, mais avec en plus le +mot `[0..5]`. Plutôt qu'une référence vers tout le `String`, c'est une +référence à une partie du `String`. La syntaxe `début..fin` est une intervalle +qui commence à `start` et comprends la suite jusqu'à `end` exclus. + + + +Nous pouvons créer des slices en utilisant une intervalle entre crochets en +spécifiant `[index_debut..index_fin]`, où `index_debut` est la première +position dans le slice et `index_fin` est une position en plus que la dernière +position dans le slice. En interne, la structure de données du slice enregistre +la position de départ et la longeur du slice, ce qui correspond à `index_fin` +moins `index_debut`. Donc dans le cas de `let world = &s[6..11];`, `world` va +être un slice qui a un pointeur vers le sixième octet de `s` et une longueur +de 5. + + + +L'illustration 4-6 montre cela dans un diagramme. + + +world containing a pointer to the 6th byte of String s and a length 5 +--> + +world contient un pointeur vers le sixième octet du String s et une longueur de 5 + + + +Illustration 4-6 : un slice de String qui pointe vers +une partie de `String` + + + +Avec la syntaxe d'interface `..` de Rust, si vous voulez commencer au premier +index (zéro), vous pouvez ne rien mettre avant les deux points. Autrement dit, +ceci est identique : + + + +```rust +let s = String::from("hello"); + +let slice = &s[0..2]; +let slice = &s[..2]; +``` + + + +De la même manière, si votre slice contient les derniers octets du `String`, +vous pouvez ne rien mettre à la fin. Cela veut dire que ces deux instructions +sont identiques : + + + +```rust +let s = String::from("hello"); + +let len = s.len(); + +let slice = &s[3..len]; +let slice = &s[3..]; +``` + + + +Vous pouvez aussi ne mettre aucune limite pour faire un slice de toute la +chaîne de caractères. Donc ces deux cas sont identiques : + + + +```rust +let s = String::from("hello"); + +let len = s.len(); + +let slice = &s[0..len]; +let slice = &s[..]; +``` + + + +> Note : Les indexes de l'intervalle d'un slice d'un String doivent toujours +> être des valeurs compatibles avec l'UTF-8. Si vous essayez de créer un slice +> d'une chaîne de caractères au millieu d'un caractère codé sur plusieurs +> octets, votre programme va se fermer avec une erreur. Pour que nous abordions +> simplement les slice de chaînes de caractères, nous supposerons que nous +> utilisons l'ASCII uniquement dans cette section; nous discuterons plus en +> détails de la gestion UTF-8 dans la section “Chaînes de caractères” au +> chapitre 8. + + + +Avec toutes ces informations, essayons de ré-écrire `first_word` pour retourner +un slice. Le type pour les “slices de chaînes de caractères” s'écrit `&str` : + + + +Nom du fichier : src/main.rs + + + +```rust +fn first_word(s: &String) -> &str { + let bytes = s.as_bytes(); + + for (i, &item) in bytes.iter().enumerate() { + if item == b' ' { + return &s[0..i]; + } + } + + &s[..] +} +``` + + + +Nous récupérons l'index de la fin du mot de la même façon que nous l'avons fait +dans l'entrée 4-5, en cherchant la première occurrence d'un espace. Quand nous +trouvons un espace, nous retournons un slice de chaîne de caractère en +utilisant le début de la chaîne de caractères et l'index de l'espace comme +indices de début et fin. + + + +Maintenant, quand nous appelons `first_word`, nous récupérons une seule valeur +qui est liée à la donnée de base. La valeur est construite avec une référence +vers le point de départ du slice et nombre d'éléments dans le slice. + + + +Retourner un slice fonctionnerait aussi pour une fonction `second_word` : + + + +```rust,ignore +fn second_word(s: &String) -> &str { +``` + + + +Nous avons maintenant une API simple qui est bien plus difficile à perturber, +puisque le compilateur va s'assurer que les références dans le `String` seront +toujours en vigueur. Souvenez-vous du bogue dans le programme de l'entrée 4-6, +quand nous avions un index vers la fin du premier mot mais qu'ensuite nous +avions vidé la chaîne de caractères et que notre index n'était plus valide ? +Ce code était logiquement incorrect, mais nous n'avons pas immédiatement vu +d'erreurs. Les problèmes vont arriver plus tard si nous essayons d'utiliser +l'index du premier mot avec une chaîne de caractère qui a été vidée. Les slices +rendent ce bogue impossible et nous fait savoir bien plus tôt quand nous avons +un problème avec notre code. Utiliser la version avec le slice de `first_word` +va lever une erreur au moment de la compilation : + + + +Nom du fichier : src/main.rs + + + +```rust,ignore +fn main() { + let mut s = String::from("hello world"); + + let word = first_word(&s); + + s.clear(); // Erreur ! +} +``` + + + +Voici l'erreur du compilateur : + + + +```text +error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable + --> src/main.rs:6:5 + | +4 | let word = first_word(&s); + | - immutable borrow occurs here +5 | +6 | s.clear(); // Error! + | ^ mutable borrow occurs here +7 | } + | - immutable borrow ends here +``` + + + +Rappellons-nous que d'après les règles de référencement, si nous avons une +référence immuable vers quelque chose, nous ne pouvons pas avoir une référence +modifiable en même temps. Etant donné que `clear` a besoin de raccourcir le +`String`, il essaye de prendre une référence modifiable, ce qui échoue. Non +seulement Rust a simplifié l'utilisation de notre API, mais il a aussi éliminé +une catégorie entière d'erreurs au moment de la compilation ! + + + +#### Les chaînes de caractères pures sont des Slices + + + +Souvenez-vous lorsque nous avons vu les chaînes des caractères pures qui +étaient enregistrées dans le binaire. Maintenant que nous connaissons les +slices, nous pouvons comprendre comme il faut les chaînes des caractères pures. + + + +```rust +let s = "Hello, world!"; +``` + + + +Ici, le type de `s` est un `&str` : c'est un slice qui pointe vers un endroit +spécifique du binaire. C'est pourquoi les chaînes des caractères pures sont +immuables; `&str` est une référence immuable. + + + +#### Des slices de chaînes de caractères en paramètres + + + +Apprendre que vous pouvez utiliser des slices de texte et de `String` nous +amène à apporter quelques améliorations sur `first_word`, voici sa signature : + + + +```rust,ignore +fn first_word(s: &String) -> &str { +``` + + + +Un Rustacéen plus expérimenté écrirait plutôt la ligne suivante, car cela nous +permet d'utiliser la même fonction sur les `String` et les `&str` : + + + +```rust,ignore +fn first_word(s: &str) -> &str { +``` + + + +Listing 4-9: Improving the `first_word` function by using +a string slice for the type of the `s` parameter + + + +Si nous avions un slice de chaîne de caractères, nous pouvons lui envoyer +directement. Si nous avions un `String`, nous pourrions envoyer un slice de +tout le `String`. Concevoir une fonction pour prendre un slice de chaîne de +caractères plutôt qu'une référence à une chaîne de caractères rend notre API +plus générique et plus utile sans perdre aucune fonctionnalité : + + + +Nom du fichier : src/main.rs + + + +```rust +# fn first_word(s: &str) -> &str { +# let bytes = s.as_bytes(); +# +# for (i, &item) in bytes.iter().enumerate() { +# if item == b' ' { +# return &s[0..i]; +# } +# } +# +# &s[..] +# } +fn main() { + let my_string = String::from("hello world"); + + // first_word travaille avec un slice de `String` + let word = first_word(&my_string[..]); + + let my_string_literal = "hello world"; + + // first_word travaille avec un slice de chaîne de caractères pure + let word = first_word(&my_string_literal[..]); + + // puisque les chaînes de caractères *sont* déjà des slices de chaînes + // de caractères, ceci fonctionne aussi, sans la syntaxe de slice ! + let word = first_word(my_string_literal); +} +``` + + + +### Les autres slices + + + +Les slices de chaînes de caractères, comme vous pouvez l'imaginer, sont +spécifiques aux chaînes de caractères. Mais il y a aussi un type plus +générique. Admettons ce tableau : + + + +```rust +let a = [1, 2, 3, 4, 5]; +``` + + + +Comme nous pouvons nous référer à une partie de chaîne de caractères, nous +pouvons nous référer à une partie d'un tableau et nous le faisons comme ceci : + + + +```rust +let a = [1, 2, 3, 4, 5]; + +let slice = &a[1..3]; +``` + + + +Ce slice est de type `&[i32]`. Il fonctionne de la même manière que les slices +de chaînes de caractères, en enregistrant une référence vers le premier élément +et une longueur. Vous pouvez utiliser ce type de slice pour tous les autres +types de collections. Nous discuterons de ces collections en détail quand nous +verrons les vecteurs au Chapitre 8. + + + +## Résumé + + + +Les concepts d'appartenance, d'emprunt, et les slices garantissent la sécurité +de la mémoire dans les programmes Rust au moment de la compilation. Le langage +Rust vous donne le contrôle sur l'utilisation de la mémoire comme tous les +systèmes de langages de programmation, mais avoir le propriétaire des données +qui nettoie automatiquement ces données quand il sort de la portée vous permet +de ne pas avoir à écrire et déboguer du code en plus pour avoir ce contrôle. + + + +L'appropriation influe sur de nombreux fonctionnements de Rust, donc nous +allons encore parler de ces concepts plus loin dans le livre. Allons +maintenant au chapitre suivant et regardons comment regrouper des données +ensemble dans un `struct`. + +[strings]: ch08-02-strings.html#storing-utf-8-encoded-text-with-strings diff --git a/FRENCH/src/translation-terms.md b/FRENCH/src/translation-terms.md index e21c9aeace..af26de2372 100644 --- a/FRENCH/src/translation-terms.md +++ b/FRENCH/src/translation-terms.md @@ -124,6 +124,8 @@ français. | sidebar | barre latérale | - | | signature | signature | d'une fonction | | signed | signé | - | +| `Slice` | `Slice` | - | +| slice | découpage | - | | smart pointer | pointeur intelligent | - | | snip | code inchangé masqué ici | dans un encart | | space | espace | ce mot est féminin quand on parle du caractère typographique | From be3ed43958e074d90ee2999203447de2c5366a37 Mon Sep 17 00:00:00 2001 From: Jimskapt Date: Tue, 27 Aug 2019 21:26:00 +0200 Subject: [PATCH 2/4] :ambulance: Self-proofreading ch04-03. --- FRENCH/src/SUMMARY.md | 2 +- FRENCH/src/ch04-03-slices.md | 448 ++++++++++++++++---------------- FRENCH/src/img/trpl04-06.svg | 115 ++++++++ FRENCH/src/translation-terms.md | 2 + 4 files changed, 349 insertions(+), 218 deletions(-) create mode 100644 FRENCH/src/img/trpl04-06.svg diff --git a/FRENCH/src/SUMMARY.md b/FRENCH/src/SUMMARY.md index d66c9dd786..4582e6ac31 100644 --- a/FRENCH/src/SUMMARY.md +++ b/FRENCH/src/SUMMARY.md @@ -14,4 +14,4 @@ - [Programmer un jeu de devinettes](ch02-00-guessing-game-tutorial.md) -- [Le type Slice](ch04-03-slices.md) +- [Le type de découpage](ch04-03-slices.md) diff --git a/FRENCH/src/ch04-03-slices.md b/FRENCH/src/ch04-03-slices.md index f617e28a6d..6ff0a6dc16 100644 --- a/FRENCH/src/ch04-03-slices.md +++ b/FRENCH/src/ch04-03-slices.md @@ -2,7 +2,7 @@ ## The Slice Type --> -## Le type Slice +## Le type de découpage -Un autre type de données qui n'applique pas le principe d'appartenance est le -*slice*. Un slice vous permet d'avoir une référence vers une suite continue -d'éléments dans une collection plutôt que toute la collection. +Un autre type de données qui ne prend pas possession est le *découpage*. Un +découpage vous permet d'obtenir une référence vers une suite continue d'éléments +d'une collection plutôt que toute la collection. -Voici un petit problème de programmation : écrire une fonction qui prend une +Voici un petit problème de programmation : écrire une fonction qui prend une chaîne de caractères et retourne le premier mot qu'elle trouve dans cette chaîne. Si la fonction ne trouve pas d'espace dans la chaîne, cela veut dire que toute la chaîne est un seul mot, donc la chaîne en entier doit être @@ -31,7 +31,7 @@ retournée. Let’s think about the signature of this function: --> -Imaginons la signature de cette fonction : +Imaginons la signature de cette fonction : ```rust,ignore -fn first_word(s: &String) -> ? +fn premier_mot(s: &String) -> ? ``` -Cette fonction, `first_word`, prends un `&String` comme paramètre. Nous ne -voulons pas se l'approprier, donc tout va bien. Mais que devons-nous -retourner ? Nous n'avons pas de moyen de désigner une *partie* de chaîne de -caractères. Cependant, nous pouvons retourner l'index de la fin du mot. -Essayons cela dans l'entrée 4-5 : +Cette fonction, `premier_mot`, prend un `&String` comme paramètre. Nous ne +voulons pas en prendre possession, donc c'est ce qu'il nous faut. Mais que +devons-nous retourner ? Nous n'avons pas de moyens de désigner une *partie* +d'une chaîne de caractères. Cependant, nous pouvons retourner l'indice de la +fin du mot. Essayons cela, dans l'encart 4-7 : -Nom du fichier : src/main.rs +Fichier : src/main.rs ```rust -fn first_word(s: &String) -> usize { - let bytes = s.as_bytes(); +fn premier_mot(s: &String) -> usize { + let octets = s.as_bytes(); - for (i, &item) in bytes.iter().enumerate() { - if item == b' ' { + for (i, &element) in octets.iter().enumerate() { + if element == b' ' { return i; } } @@ -97,8 +97,8 @@ fn first_word(s: &String) -> usize { byte index value into the `String` parameter --> -Entrée 4-5 : la fonction `first_word` qui retourne la -valeur d'index d'octet dans le paramètre `String` +Encart 4-7 : La fonction `premier_mot` qui retourne un +indice d'octet provenant du paramètre `String` -Regardons un peu plus en détail ce code. Puisque nous avons besoin de parcourir -le `String` éléments par éléments et vérifier si leur valeur est un espace, -nous allons convertir notre `String` en tableau d'octets en utilisant la -méthode `as_bytes` : +Comme nous avons besoin de parcourir la `String` élément par élément et de +vérifier si la valeur est un espace, nous allons convertir notre `String` en un +tableau d'octets en utilisant la méthode `as_bytes` : ```rust,ignore -let bytes = s.as_bytes(); +let octets = s.as_bytes(); ``` Ensuite, nous créons un itérateur sur le tableau d'octets en utilisant la -méthode `iter` : +méthode `iter` : ```rust,ignore -for (i, &item) in bytes.iter().enumerate() { +for (i, &element) in octets.iter().enumerate() { ``` -Nous discuterons plus en détail des itérateur dans le chapitre 13. Pour le -moment, sachez que ce `iter` est une méthode qui retourne chaque élément dans -une collection, et que `enumerate` enveloppe le résultat de `iter` et retourne -plutôt chaque élément comme une partie d'un tuple. Le premier élément du tuple -retourné est l'index, et le second élément est une référence vers l'élément. -C'est un peu plus pratique que de calculer les index par nous-mêmes. +Nous aborderons plus en détail les itérateurs dans le chapitre 13. Pour le +moment, sachez que `iter` est une méthode qui retourne chaque élément d'une +collection, et que `enumerate` transforme le résultat de `iter` pour retourner +plutôt chaque élément comme un tuple. Le premier élément du tuple retourné par +`enumerate` est l'indice, et le second élément est une référence vers l'élément. +C'est un peu plus pratique que de calculer les indices par nous-mêmes. -Comme la méthode `enumerate` retourne un tuple, ne pouvons utiliser une -technique pour décomposer ce tuple, comme nous pourrions le faire n'importe où -avec Rust. Donc dans la boucle `for`, nous précisions un schéma qui indique que -nous définissons `i` pour l'index à partir du tuple et `&item` for chaque octet -dans le tuple. Comme nous obtenons une référence vers l'élément avec -`.iter().enumerate()`, nous utilisons `&` dans le schéma. +Comme la méthode `enumerate` retourne un tuple, ne pouvons utiliser des motifs +pour déstructurer ce tuple, comme nous pourrions le faire n'importe où avec +Rust. Donc dans la boucle `for`, nous précisons un motif qui indique que nous +définissons `i` pour l'indice à partir du tuple et `&element` pour l'octet dans +le tuple. Comme nous obtenons une référence vers l'élément avec +`.iter().enumerate()`, nous utilisons `&` dans le motif. -Nous recherchons l'octet qui représente l'espace en utilisant la syntaxe des -mots binaires. Si nous trouvons un espace, nous retournons sa position. Sinon, -nous retournons la taille du string en utilisant `s.len()` : +Avec la boucle `for`, nous recherchons l'octet qui représente l'espace en +utilisant la syntaxe des mots binaires. Si nous trouvons un espace, nous +retournons sa position. Sinon, nous retournons la taille de la chaîne en +utilisant `s.len()` : -Nous avons maintenant une façon de trouver l'index de la fin du premier mot +Nous avons maintenant une façon de trouver l'indice de la fin du premier mot dans la chaîne de caractères, mais il y a un problème. Nous retournons un -`usize` seul, mais il n'est important que lorsqu'il est mis en rapport avec -le `&String`. Autrement dit, parce qu'il a une valeur séparée du `String`, il -n'y a pas de garantie qu'il sera toujours valide dans le futur. Imaginons -le programme dans l'entrée 4-6 qui utilise la fonction de l'entrée 4-5 : +`usize` tout seul, mais il n'a du sens que lorsqu'il est lié au `&String`. +Autrement dit, comme il a une valeur séparée de la `String`, il n'y a pas de +garantie qu'il restera toujours valide dans le futur. Imaginons le programme +dans l'encart 4-8 qui utilise la fonction `premier_mot` de l'encart 4-7 : -Nom du fichier : src/main.rs +Fichier : src/main.rs ```rust -# fn first_word(s: &String) -> usize { -# let bytes = s.as_bytes(); +# fn premier_mot(s: &String) -> usize { +# let octets = s.as_bytes(); # -# for (i, &item) in bytes.iter().enumerate() { -# if item == b' ' { +# for (i, &element) in octets.iter().enumerate() { +# if element == b' ' { # return i; # } # } @@ -263,12 +264,12 @@ fn main() { fn main() { let mut s = String::from("hello world"); - let word = first_word(&s); // word aura 5 comme valeur. + let mot = premier_mot(&s); // la variable mot aura 5 comme valeur. - s.clear(); // Ceci vide le String, il faut maintenant "". + s.clear(); // ceci vide la String, elle vaut maintenant "". - // word a toujours la valeur 5 ici, mais il n'y a plus de chaîne qui donne - // du sens à la valeur 5. word est maintenant complètement invalide ! + // mot a toujours la valeur 5 ici, mais il n'y a plus de chaîne qui donne + // du sens à la valeur 5. mot est maintenant complètement invalide ! } ``` @@ -277,8 +278,8 @@ fn main() { `first_word` function and then changing the `String` contents --> -Entrée 4-6 : On stocke le résultat de l'appel à la -fonction `first_word` et ensuite on change le contenu du `String` +Encart 4-8 : On stocke le résultat de l'appel à la +fonction `premier_mot` et ensuite on change le contenu de la `String` -Ce programme se compile sans aucune erreur et serait toujours OK si nous -utilisions `word` après avoir appelé `s.clear()`. `word` n'est pas du tout lié -à l'état de `s`, donc `word` contient toujours la valeur `5`. Nous pourrions +Ce programme se compile sans aucune erreur et le serait toujours si nous +utilisions `mot` après avoir appelé `s.clear()`. Comme `mot` n'est pas du tout +lié à `s`, `mot` contient toujours la valeur `5`. Nous pourrions utiliser cette valeur `5` avec la variable `s` pour essayer d'en extraire le premier mot, mais cela serait un bogue, car le contenu de `s` a changé depuis -que nous avons enregistré `5` dans `word`. +que nous avons enregistré `5` dans `mot`. -Se préoccuper en permanence que l'index dans `word` ne soit plus synchronisé -avec les données dans `s` est fastidieux et source d'erreur ! La gestion de ces -index est encore plus risquée si nous écrivons une fonction second_word. Sa -signature ressemblerait à quelque chose comme ceci : +Se préoccuper en permanence que l'indice présent dans `mot` ne soit plus +synchronisé avec les données présentes dans `s` est fastidieux et source +d'erreur ! La gestion de ces indices est encore plus risquée si nous écrivons +une fonction `second_mot`. Sa signature ressemblerait à ceci : ```rust,ignore -fn second_word(s: &String) -> (usize, usize) { +fn second_mot(s: &String) -> (usize, usize) { ``` -Maintenant nous gérons un index de début *et* un index de fin, et nous avons -encore plus de valeurs qui sont calculées à partir de la donnée dans un -état particulier, mais qui n'est pas lié à son état en temps réel. Nous avons -maintenant trois variables isolées qui ont besoin d'être maintenu à jour. +Maintenant nous avons un indice de début *et* un indice de fin, donc nous avons +encore plus de valeurs qui sont calculées à partir de la donnée à un instant +donné, mais qui n'est pas en temps réel. Nous avons maintenant trois variables +isolées qui ont besoin d'être maintenues à jour. -Heureusement, Rust a une solution pour ce problème : les slices de chaînes de -caractères. +Heureusement, Rust a une solution pour ce problème : les découpages de chaînes +de caractères. -### Les slices de chaînes de caractères +### Les découpages de chaînes de caractères -Un *slice de chaîne de caractère* est une référence à une partie d'un `String`, -et ressemble à ceci : +Un *découpage de chaîne de caractère* est une référence à une partie +d'une `String`, et ressemble à ceci : -Ce serait comme prendre une référence pour tout le `String`, mais avec en plus le -mot `[0..5]`. Plutôt qu'une référence vers tout le `String`, c'est une -référence à une partie du `String`. La syntaxe `début..fin` est une intervalle -qui commence à `start` et comprends la suite jusqu'à `end` exclus. +Cela ressemble à une référence pour toute la `String`, mais avec la partie +`[0..5]` en plus. Plutôt que d'être une référence vers toute la `String`, c'est +une référence vers une partie de la `String`. -Nous pouvons créer des slices en utilisant une intervalle entre crochets en -spécifiant `[index_debut..index_fin]`, où `index_debut` est la première -position dans le slice et `index_fin` est une position en plus que la dernière -position dans le slice. En interne, la structure de données du slice enregistre -la position de départ et la longeur du slice, ce qui correspond à `index_fin` -moins `index_debut`. Donc dans le cas de `let world = &s[6..11];`, `world` va -être un slice qui a un pointeur vers le sixième octet de `s` et une longueur -de 5. +Nous pouvons créer des découpages en utilisant un intervalle entre crochets en +spécifiant `[indice_debut..indice_fin]`, où `indice_debut` est la première +position dans le découpage et `indice_fin` est la dernière position dans le +découpage plus une position. En interne, la structure de données du découpage +enregistre la position de départ et la longueur du découpage, ce qui correspond +à `indice_fin` moins `indice_debut`. Donc dans le cas du +`let world = &s[6..11];`, `world` va être un découpage qui a un pointeur vers le +7e octet de `s` et une longueur de 5. -L'illustration 4-6 montre cela dans un diagramme. +L'illustration 4-6 montre ceci dans un schéma. - + -world contient un pointeur vers le sixième octet du String s et une longueur de 5 +world contient un pointeur vers le 6ième octet de la String s et une longueur de 5 -Illustration 4-6 : un slice de String qui pointe vers -une partie de `String` +Illustration 4-6 : Un découpage d'une chaîne qui pointe +vers une partie d'une `String` -Avec la syntaxe d'interface `..` de Rust, si vous voulez commencer au premier -index (zéro), vous pouvez ne rien mettre avant les deux points. Autrement dit, -ceci est identique : +Avec la syntaxe d'intervalle `..` de Rust, si vous voulez commencer au premier +indice (zéro), vous pouvez ne rien mettre avant les deux points. Autrement dit, +ceci est identique : -De la même manière, si votre slice contient les derniers octets du `String`, -vous pouvez ne rien mettre à la fin. Cela veut dire que ces deux instructions -sont identiques : +De la même manière, si votre découpage contient les derniers octets de la +`String`, vous pouvez ne rien mettre à la fin. Cela veut dire que ces deux +ceci revient au même : -Vous pouvez aussi ne mettre aucune limite pour faire un slice de toute la -chaîne de caractères. Donc ces deux cas sont identiques : +Vous pouvez aussi ne mettre aucune limite pour créer un découpage de toute la +chaîne de caractères. Ces deux cas sont donc identiques : -> Note : Les indexes de l'intervalle d'un slice d'un String doivent toujours -> être des valeurs compatibles avec l'UTF-8. Si vous essayez de créer un slice -> d'une chaîne de caractères au millieu d'un caractère codé sur plusieurs -> octets, votre programme va se fermer avec une erreur. Pour que nous abordions -> simplement les slice de chaînes de caractères, nous supposerons que nous -> utilisons l'ASCII uniquement dans cette section; nous discuterons plus en -> détails de la gestion UTF-8 dans la section “Chaînes de caractères” au -> chapitre 8. +> Remarque : Les indices de l'intervalle d'un découpage d'une chaîne de +> caractères doivent toujours se trouver dans les zones acceptables de +> séparation des caractères encodés en UTF-8. Si vous essayez de créer un +> découpage d'une chaîne de caractères qui s'arrête au milieu d'un caractère +> encodé sur plusieurs octets, votre programme va se fermer avec une erreur. +> Afin de simplifier l'explication des découpages de chaînes de caractères, nous +> utiliserons uniquement l'ASCII dans cette section; nous verons la gestion de +> l'UTF-8 dans une section du [chapitre 8][strings]. -Avec toutes ces informations, essayons de ré-écrire `first_word` pour retourner -un slice. Le type pour les “slices de chaînes de caractères” s'écrit `&str` : +Maintenant que nous savons tout cela, essayons de ré-écrire `premier_mot` pour +retourner un découpage. Le type pour les “découpages de chaînes de caractères” +s'écrit `&str` : -Nom du fichier : src/main.rs +Fichier : src/main.rs ```rust -fn first_word(s: &String) -> &str { - let bytes = s.as_bytes(); +fn premier_mot(s: &String) -> &str { + let octets = s.as_bytes(); - for (i, &item) in bytes.iter().enumerate() { - if item == b' ' { + for (i, &element) in octets.iter().enumerate() { + if element == b' ' { return &s[0..i]; } } @@ -565,10 +566,10 @@ return a string slice using the start of the string and the index of the space as the starting and ending indices. --> -Nous récupérons l'index de la fin du mot de la même façon que nous l'avons fait -dans l'entrée 4-5, en cherchant la première occurrence d'un espace. Quand nous -trouvons un espace, nous retournons un slice de chaîne de caractère en -utilisant le début de la chaîne de caractères et l'index de l'espace comme +Nous récupérons l'indice de la fin du mot de la même façon que nous l'avions +fait dans l'encart 4-7, en cherchant la première occurrence d'un espace. Lorsque +nous trouvons un espace, nous retournons un découpage de la chaîne de caractère +en utilisant le début de la chaîne de caractères et l'indice de l'espace comme indices de début et fin. -Maintenant, quand nous appelons `first_word`, nous récupérons une seule valeur +Désormais quand nous appelons `premier_mot`, nous récupérons une seule valeur qui est liée à la donnée de base. La valeur est construite avec une référence -vers le point de départ du slice et nombre d'éléments dans le slice. +vers le point de départ du découpage et avec le nombre d'éléments dans le +découpage. -Retourner un slice fonctionnerait aussi pour une fonction `second_word` : +Retourner un découpage fonctionnerait aussi pour une fonction `second_mot` : ```rust,ignore -fn second_word(s: &String) -> &str { +fn second_mot(s: &String) -> &str { ``` Nous avons maintenant une API simple qui est bien plus difficile à perturber, -puisque le compilateur va s'assurer que les références dans le `String` seront -toujours en vigueur. Souvenez-vous du bogue dans le programme de l'entrée 4-6, -quand nous avions un index vers la fin du premier mot mais qu'ensuite nous -avions vidé la chaîne de caractères et que notre index n'était plus valide ? -Ce code était logiquement incorrect, mais nous n'avons pas immédiatement vu -d'erreurs. Les problèmes vont arriver plus tard si nous essayons d'utiliser -l'index du premier mot avec une chaîne de caractère qui a été vidée. Les slices -rendent ce bogue impossible et nous fait savoir bien plus tôt quand nous avons -un problème avec notre code. Utiliser la version avec le slice de `first_word` -va lever une erreur au moment de la compilation : +puisque le compilateur va s'assurer que les références dans la `String` seront +toujours en vigueur. Souvenez-vous du bogue du programme de l'encart 4-8, +lorsque nous avions un indice vers la fin du premier mot mais qu'ensuite nous +avions vidé la chaîne de caractères et que notre index n'était plus valide ? Ce +code était logiquement incorrect, mais ne montrait pas immédiatement une erreur. +Les problèmes apparaîtront plus tard si nous essayons d'utiliser l'indice du +premier mot avec une chaîne de caractère qui a été vidée. Les découpages rendent +ce bogue impossible et nous signale bien plus tôt que nous avons un problème +avec notre code. Utiliser la version avec le découpage de `premier_mot` va +afficher une erreur au moment de la compilation : -Nom du fichier : src/main.rs +Fichier : src/main.rs -```rust,ignore +```rust,ignore,does_not_compile fn main() { let mut s = String::from("hello world"); - let word = first_word(&s); + let mot = premier_mot(&s); + + s.clear(); // Erreur ! - s.clear(); // Erreur ! + println!("Le premier mot est : {}", mot); } ``` @@ -655,7 +659,7 @@ fn main() { Here’s the compiler error: --> -Voici l'erreur du compilateur : +Voici l'erreur du compilateur : src/main.rs:6:5 - | -4 | let word = first_word(&s); - | - immutable borrow occurs here -5 | -6 | s.clear(); // Error! - | ^ mutable borrow occurs here -7 | } - | - immutable borrow ends here + --> src/main.rs:18:5 + | +16 | let mot = premier_mot(&s); + | -- immutable borrow occurs here +17 | +18 | s.clear(); // Erreur ! + | ^^^^^^^^^ mutable borrow occurs here +19 | +20 | println!("Le premier mot est : {}", mot); + | --- immutable borrow later used here ``` -Rappellons-nous que d'après les règles de référencement, si nous avons une -référence immuable vers quelque chose, nous ne pouvons pas avoir une référence -modifiable en même temps. Etant donné que `clear` a besoin de raccourcir le -`String`, il essaye de prendre une référence modifiable, ce qui échoue. Non -seulement Rust a simplifié l'utilisation de notre API, mais il a aussi éliminé -une catégorie entière d'erreurs au moment de la compilation ! +Rappellons-nous que d'après les règles d'emprunt, si nous avons une référence +immuable vers quelque chose, nous ne pouvons pas avoir une référence mutable +en même temps. Etant donné que `clear` a besoin de modifier la `String`, il a +besoin d'une référence mutable. Rust interdit cette situation, et la compilation +échoue. Non seulement Rust a simplifié l'utilisation de notre API, mais il a +aussi éliminé une catégorie entière d'erreurs au moment de la compilation ! -#### Les chaînes de caractères pures sont des Slices +#### Les chaînes de caractères pures sont des découpages -Souvenez-vous lorsque nous avons vu les chaînes des caractères pures qui +Rappellez-vous lorsque nous avons appris que les chaînes de caractères pures étaient enregistrées dans le binaire. Maintenant que nous connaissons les -slices, nous pouvons comprendre comme il faut les chaînes des caractères pures. +découpages, nous pouvons désormais comprendre les chaînes de caractères pures. -Ici, le type de `s` est un `&str` : c'est un slice qui pointe vers un endroit -spécifique du binaire. C'est pourquoi les chaînes des caractères pures sont -immuables; `&str` est une référence immuable. +Ici, le type de `s` est un `&str` : c'est un découpage qui pointe vers un +endroit précis du binaire. C'est aussi la raison pour laquelle les chaînes de +caractères pures sont immuables; `&str` est une référence immuable. -#### Des slices de chaînes de caractères en paramètres +#### Les découpages de chaînes de caractères en paramètres -Apprendre que vous pouvez utiliser des slices de texte et de `String` nous -amène à apporter quelques améliorations sur `first_word`, voici sa signature : +Savoir que vous pouvez utiliser des découpages de chaînes de caractères pures et +des `String` nous invite à apporter une petite amélioration sur `premier_mot`, +dont voici sa signature : ```rust,ignore -fn first_word(s: &String) -> &str { +fn premier_mot(s: &String) -> &str { ``` -Un Rustacéen plus expérimenté écrirait plutôt la ligne suivante, car cela nous -permet d'utiliser la même fonction sur les `String` et les `&str` : +Un Rustacé plus expérimenté écrirait plutôt la signature de l'encart 4_9, car +cela nous permet d'utiliser la même fonction sur les `&String` et aussi les +`&str` : ```rust,ignore -fn first_word(s: &str) -> &str { +fn premier_mot(s: &str) -> &str { ``` -Listing 4-9: Improving the `first_word` function by using -a string slice for the type of the `s` parameter +Encart 4-9 : Amélioration de la fonction `premier_mot` en +utilisant un découpage de chaîne de caractère comme type du paramètre `s` -Si nous avions un slice de chaîne de caractères, nous pouvons lui envoyer -directement. Si nous avions un `String`, nous pourrions envoyer un slice de -tout le `String`. Concevoir une fonction pour prendre un slice de chaîne de -caractères plutôt qu'une référence à une chaîne de caractères rend notre API -plus générique et plus utile sans perdre aucune fonctionnalité : +Si nous avons un découpage de chaîne de caractères, nous pouvons lui donner +directement. Si nous avons une `String`, nous pouvons envoyer un découpage de +toute la `String`. Concevoir une fonction afin de prendre un découpage de chaîne +de caractères plutôt qu'une référence à une `String` rend notre API plus +générique et plus utile sans perdre aucune fonctionnalité : -Nom du fichier : src/main.rs +Fichier : src/main.rs ```rust -# fn first_word(s: &str) -> &str { -# let bytes = s.as_bytes(); +# fn premier_mot(s: &str) -> &str { +# let octets = s.as_bytes(); # -# for (i, &item) in bytes.iter().enumerate() { -# if item == b' ' { +# for (i, &element) in octets.iter().enumerate() { +# if element == b' ' { # return &s[0..i]; # } # } @@ -850,19 +857,20 @@ fn main() { # &s[..] # } fn main() { - let my_string = String::from("hello world"); + let ma_string = String::from("hello world"); - // first_word travaille avec un slice de `String` - let word = first_word(&my_string[..]); + // premier_mot travaille avec un découpage de `String` + let mot = premier_mot(&ma_string[..]); - let my_string_literal = "hello world"; + let ma_chaine_pure = "hello world"; - // first_word travaille avec un slice de chaîne de caractères pure - let word = first_word(&my_string_literal[..]); + // premier_mot travaille avec un découpage de chaîne de caractères pure + let mot = premier_mot(&ma_chaine_pure[..]); - // puisque les chaînes de caractères *sont* déjà des slices de chaînes - // de caractères, ceci fonctionne aussi, sans la syntaxe de slice ! - let word = first_word(my_string_literal); + // Comme les chaînes de caractères pures *sont* déjà des découpages de + // chaînes de caractères, cela fonctionne aussi, sans la syntaxe de + // découpage ! + let mot = premier_mot(ma_chaine_pure); } ``` @@ -870,16 +878,16 @@ fn main() { ### Other Slices --> -### Les autres slices +### Les autres découpages -Les slices de chaînes de caractères, comme vous pouvez l'imaginer, sont -spécifiques aux chaînes de caractères. Mais il y a aussi un type plus -générique. Admettons ce tableau : +Les découpages de chaînes de caractères, comme vous pouvez l'imaginer, sont +spécifiques aux chaînes de caractères. Mais il existe aussi un type plus +générique. Imaginons ce tableau de données : -Comme nous pouvons nous référer à une partie de chaîne de caractères, nous -pouvons nous référer à une partie d'un tableau et nous le faisons comme ceci : +Comme nous pouvons nous référer à un échantillon d'une chaîne de caractères, +nous pouvons nous référer à une partie d'un tableau. Nous pouvons le faire comme +ceci : -Ce slice est de type `&[i32]`. Il fonctionne de la même manière que les slices -de chaînes de caractères, en enregistrant une référence vers le premier élément -et une longueur. Vous pouvez utiliser ce type de slice pour tous les autres -types de collections. Nous discuterons de ces collections en détail quand nous -verrons les vecteurs au Chapitre 8. +Ce découpage est de type `&[i32]`. Il fonctionne de la même manière que les +découpages de chaînes de caractères, en enregistrant une référence vers le +premier élément et une longueur. Vous réutiliserez ce type de découpage pour +toutes les autres types de collections. Nous aborderons ces collections en +détail quand lorsque nous verrons les vecteurs au chapitre 8. -Les concepts d'appartenance, d'emprunt, et les slices garantissent la sécurité -de la mémoire dans les programmes Rust au moment de la compilation. Le langage -Rust vous donne le contrôle sur l'utilisation de la mémoire comme tous les -systèmes de langages de programmation, mais avoir le propriétaire des données -qui nettoie automatiquement ces données quand il sort de la portée vous permet -de ne pas avoir à écrire et déboguer du code en plus pour avoir ce contrôle. +Les concepts de possession, d'emprunt, et les découpages garantissent la +sécurité de la mémoire dans les programmes Rust au moment de la compilation. Le +langage Rust vous donne le contrôle sur l'utilisation de la mémoire comme tous +les autres systèmes de langages de programmation, mais celui qui possède les +données nettoie automatiquement ces données quand il sort de la portée, et cela +vous permet de ne pas avoir à écrire et déboguer du code en plus pour avoir +cette fonctionnalité. -L'appropriation influe sur de nombreux fonctionnements de Rust, donc nous -allons encore parler de ces concepts plus loin dans le livre. Allons -maintenant au chapitre suivant et regardons comment regrouper des données -ensemble dans un `struct`. +La possession influe sur de nombreuses autres fonctionnalités de Rust, c'est +pourquoi nous allons encore parler de ces concepts plus loin dans le livre. +Passons maintenant au chapitre 5 et découvrons comment regrouper des données +ensemble dans une `struct`. + + +[strings]: ch08-02-strings.html diff --git a/FRENCH/src/img/trpl04-06.svg b/FRENCH/src/img/trpl04-06.svg new file mode 100644 index 0000000000..e64415fe43 --- /dev/null +++ b/FRENCH/src/img/trpl04-06.svg @@ -0,0 +1,115 @@ + + + + + + +%3 + + + +table0 + +world + +name + +value + +ptr + + +len + +5 + + + +table4 + +index + +value + +0 + +h + +1 + +e + +2 + +l + +3 + +l + +4 + +o + +5 + + + +6 + +w + +7 + +o + +8 + +r + +9 + +l + +10 + +d + + + +table0:c->table4:pointee2 + + + + + +table3 + +s + +name + +value + +ptr + + +len + +11 + +capacity + +11 + + + +table3:c->table4:pointee + + + + + diff --git a/FRENCH/src/translation-terms.md b/FRENCH/src/translation-terms.md index af26de2372..ed25c7946a 100644 --- a/FRENCH/src/translation-terms.md +++ b/FRENCH/src/translation-terms.md @@ -64,6 +64,7 @@ français. | identifier | identificateur | - | | immutability | immuabilité | - | | immutable | immuable | - | +| index | indice | - | | input/output | entrée/sortie | sigle : IO | | instance | instance | - | | instantiate | instancier | créer une instance | @@ -137,6 +138,7 @@ français. | standard output | sortie standard | - | | statement | instruction | - | | string | chaîne de caractères | - | +| string literal | chaîne de caractères pure | - | | `String` | `String` | nom féminin (une `String`) | | struct | structure | - | | submodule | sous-module | - | From e50cfb0e4c326091e8aac2f9667edfa166221fde Mon Sep 17 00:00:00 2001 From: Jimskapt Date: Tue, 3 Sep 2019 19:10:11 +0200 Subject: [PATCH 3/4] :bug: Correcting non-breaking spaces on ch04-03. --- FRENCH/src/ch04-03-slices.md | 86 ++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/FRENCH/src/ch04-03-slices.md b/FRENCH/src/ch04-03-slices.md index 6ff0a6dc16..d8c9f6f1f2 100644 --- a/FRENCH/src/ch04-03-slices.md +++ b/FRENCH/src/ch04-03-slices.md @@ -21,7 +21,7 @@ space in the string, the whole string must be one word, so the entire string should be returned. --> -Voici un petit problème de programmation : écrire une fonction qui prend une +Voici un petit problème de programmation : écrire une fonction qui prend une chaîne de caractères et retourne le premier mot qu'elle trouve dans cette chaîne. Si la fonction ne trouve pas d'espace dans la chaîne, cela veut dire que toute la chaîne est un seul mot, donc la chaîne en entier doit être @@ -31,7 +31,7 @@ retournée. Let’s think about the signature of this function: --> -Imaginons la signature de cette fonction : +Imaginons la signature de cette fonction : -Fichier : src/main.rs +Fichier : src/main.rs -Encart 4-7 : La fonction `premier_mot` qui retourne un +Encart 4-7 : La fonction `premier_mot` qui retourne un indice d'octet provenant du paramètre `String` Ensuite, nous créons un itérateur sur le tableau d'octets en utilisant la -méthode `iter` : +méthode `iter` : -Fichier : src/main.rs +Fichier : src/main.rs -Encart 4-8 : On stocke le résultat de l'appel à la +Encart 4-8 : On stocke le résultat de l'appel à la fonction `premier_mot` et ensuite on change le contenu de la `String` -Heureusement, Rust a une solution pour ce problème : les découpages de chaînes +Heureusement, Rust a une solution pour ce problème : les découpages de chaînes de caractères. Un *découpage de chaîne de caractère* est une référence à une partie -d'une `String`, et ressemble à ceci : +d'une `String`, et ressemble à ceci : -Illustration 4-6 : Un découpage d'une chaîne qui pointe +Illustration 4-6 : Un découpage d'une chaîne qui pointe vers une partie d'une `String` Vous pouvez aussi ne mettre aucune limite pour créer un découpage de toute la -chaîne de caractères. Ces deux cas sont donc identiques : +chaîne de caractères. Ces deux cas sont donc identiques : -> Remarque : Les indices de l'intervalle d'un découpage d'une chaîne de +> Remarque : Les indices de l'intervalle d'un découpage d'une chaîne de > caractères doivent toujours se trouver dans les zones acceptables de > séparation des caractères encodés en UTF-8. Si vous essayez de créer un > découpage d'une chaîne de caractères qui s'arrête au milieu d'un caractère @@ -521,13 +521,13 @@ slice. The type that signifies “string slice” is written as `&str`: Maintenant que nous savons tout cela, essayons de ré-écrire `premier_mot` pour retourner un découpage. Le type pour les “découpages de chaînes de caractères” -s'écrit `&str` : +s'écrit `&str` : -Fichier : src/main.rs +Fichier : src/main.rs -Retourner un découpage fonctionnerait aussi pour une fonction `second_mot` : +Retourner un découpage fonctionnerait aussi pour une fonction `second_mot` : -Fichier : src/main.rs +Fichier : src/main.rs -Voici l'erreur du compilateur : +Voici l'erreur du compilateur : -Ici, le type de `s` est un `&str` : c'est un découpage qui pointe vers un +Ici, le type de `s` est un `&str` : c'est un découpage qui pointe vers un endroit précis du binaire. C'est aussi la raison pour laquelle les chaînes de caractères pures sont immuables; `&str` est une référence immuable. @@ -754,7 +754,7 @@ one more improvement on `first_word`, and that’s its signature: Savoir que vous pouvez utiliser des découpages de chaînes de caractères pures et des `String` nous invite à apporter une petite amélioration sur `premier_mot`, -dont voici sa signature : +dont voici sa signature : -Encart 4-9 : Amélioration de la fonction `premier_mot` en +Encart 4-9 : Amélioration de la fonction `premier_mot` en utilisant un découpage de chaîne de caractère comme type du paramètre `s` -Fichier : src/main.rs +Fichier : src/main.rs -## Le type de découpage +## Le type slice -Un autre type de données qui ne prend pas possession est le *découpage*. Un -découpage vous permet d'obtenir une référence vers une suite continue d'éléments -d'une collection plutôt que toute la collection. +Un autre type de donnée qui ne prend pas possession est la *slice*. Une slice +vous permet d'obtenir une référence vers une séquence continue d'éléments d'une +collection plutôt que toute la collection. -Encart 4-7 : La fonction `premier_mot` qui retourne un -indice d'octet provenant du paramètre `String` +Encart 4-7 : La fonction `premier_mot` qui retourne +l'indice d'un octet provenant du paramètre `String` Comme nous avons besoin de parcourir la `String` élément par élément et de -vérifier si la valeur est un espace, nous allons convertir notre `String` en un +vérifier si la valeur est une espace, nous convertissons notre `String` en un tableau d'octets en utilisant la méthode `as_bytes` : -Comme la méthode `enumerate` retourne un tuple, ne pouvons utiliser des motifs +Comme la méthode `enumerate` retourne un tuple, nous pouvons utiliser des motifs pour déstructurer ce tuple, comme nous pourrions le faire n'importe où avec Rust. Donc dans la boucle `for`, nous précisons un motif qui indique que nous -définissons `i` pour l'indice à partir du tuple et `&element` pour l'octet dans +définissons `i` pour l'indice au sein du tuple et `&element` pour l'octet dans le tuple. Comme nous obtenons une référence vers l'élément avec `.iter().enumerate()`, nous utilisons `&` dans le motif. @@ -174,8 +173,8 @@ using the byte literal syntax. If we find a space, we return the position. Otherwise, we return the length of the string by using `s.len()`: --> -Avec la boucle `for`, nous recherchons l'octet qui représente l'espace en -utilisant la syntaxe des mots binaires. Si nous trouvons un espace, nous +Au sein de la boucle `for`, nous recherchons l'octet qui représente l'espace en +utilisant la syntaxe de littéral d'octet. Si nous trouvons une espace, nous retournons sa position. Sinon, nous retournons la taille de la chaîne en utilisant `s.len()` : @@ -191,7 +190,7 @@ s.len() --> ```rust,ignore - if item == b' ' { + if element == b' ' { return i; } } @@ -289,12 +288,12 @@ the variable `s` to try to extract the first word out, but this would be a bug because the contents of `s` have changed since we saved `5` in `word`. --> -Ce programme se compile sans aucune erreur et le serait toujours si nous +Ce programme se compile sans aucune erreur et le ferait toujours si nous utilisions `mot` après avoir appelé `s.clear()`. Comme `mot` n'est pas du tout -lié à `s`, `mot` contient toujours la valeur `5`. Nous pourrions -utiliser cette valeur `5` avec la variable `s` pour essayer d'en extraire le -premier mot, mais cela serait un bogue, car le contenu de `s` a changé depuis -que nous avons enregistré `5` dans `mot`. +lié à `s`, `mot` contient toujours la valeur `5`. Nous pourrions utiliser cette +valeur `5` avec la variable `s` pour essayer d'en extraire le premier mot, mais +cela serait un bogue, car le contenu de `s` a changé depuis que nous avons +enregistré `5` dans `mot`. -Maintenant nous avons un indice de début *et* un indice de fin, donc nous avons -encore plus de valeurs qui sont calculées à partir de la donnée à un instant -donné, mais qui n'est pas en temps réel. Nous avons maintenant trois variables -isolées qui ont besoin d'être maintenues à jour. +Maintenant, nous avons un indice de début *et* un indice de fin, donc nous avons +encore plus de valeurs qui sont calculées à partir d'une donnée dans un état +donné, mais qui ne sont pas liées du tout à l'état de cette donnée. Nous avons +maintenant trois variables isolées qui ont besoin d'être maintenues à jour. -Heureusement, Rust a une solution pour ce problème : les découpages de chaînes -de caractères. +Heureusement, Rust a une solution pour ce problème : les *slices* de chaînes de +caractères. -### Les découpages de chaînes de caractères +### Les slices de chaînes de caractères -Un *découpage de chaîne de caractère* est une référence à une partie -d'une `String`, et ressemble à ceci : - - +Une *slice de chaîne de caractères* (ou *slice de chaîne*) est une référence à +une partie d'une `String`, et ressemble à ceci : ```rust let s = String::from("hello world"); @@ -385,14 +375,14 @@ the length of the slice, which corresponds to `ending_index` minus a slice that contains a pointer to the 7th byte of `s` with a length value of 5. --> -Nous pouvons créer des découpages en utilisant un intervalle entre crochets en -spécifiant `[indice_debut..indice_fin]`, où `indice_debut` est la première -position dans le découpage et `indice_fin` est la dernière position dans le -découpage plus une position. En interne, la structure de données du découpage -enregistre la position de départ et la longueur du découpage, ce qui correspond -à `indice_fin` moins `indice_debut`. Donc dans le cas du -`let world = &s[6..11];`, `world` va être un découpage qui a un pointeur vers le -7e octet de `s` et une longueur de 5. +Nous pouvons créer des slices en utilisant un intervalle entre crochets en +spécifiant `[indice_debut..indice_fin]`, où `indice_debut` est la position du +premier octet de la slice et `indice_fin` est la position juste après le dernier +octet de la slice. En interne, la structure de données de la slice stocke la +position de départ et la longueur de la slice, ce qui correspond à `indice_fin` +moins `indice_debut`. Donc dans le cas de `let world = &s[6..11];`, `world` est +une slice qui contient un pointeur vers l'octet d'indice 6 de `s` et une +longueur de 5. + -world contient un pointeur vers le 6ième octet de la String s et une longueur de 5 +world contient un pointeur vers l'octet d'indice 6 de la String s et
+une longueur de 5 -Illustration 4-6 : Un découpage d'une chaîne qui pointe -vers une partie d'une `String` +Illustration 4-6 : Une slice de chaîne qui pointe vers +une partie d'une `String` - -```rust -let s = String::from("hello"); - -let decoupage = &s[0..2]; -let decoupage = &s[..2]; -``` -De la même manière, si votre découpage contient les derniers octets de la -`String`, vous pouvez ne rien mettre à la fin. Cela veut dire que ces deux -ceci revient au même : +De la même manière, si votre slice contient le dernier octet de la `String`, +vous pouvez ne rien mettre à la fin. Cela veut dire que ces deux cas sont +identiques : -Vous pouvez aussi ne mettre aucune limite pour créer un découpage de toute la +Vous pouvez aussi ne mettre aucune limite pour créer une slice de toute la chaîne de caractères. Ces deux cas sont donc identiques : -> Remarque : Les indices de l'intervalle d'un découpage d'une chaîne de -> caractères doivent toujours se trouver dans les zones acceptables de -> séparation des caractères encodés en UTF-8. Si vous essayez de créer un -> découpage d'une chaîne de caractères qui s'arrête au milieu d'un caractère -> encodé sur plusieurs octets, votre programme va se fermer avec une erreur. -> Afin de simplifier l'explication des découpages de chaînes de caractères, nous -> utiliserons uniquement l'ASCII dans cette section; nous verons la gestion de -> l'UTF-8 dans une section du [chapitre 8][strings]. +> Remarque : Les indices de l'intervalle d'une slice de chaîne doivent toujours +> se trouver dans les zones acceptables de séparation des caractères encodés en +> UTF-8. Si vous essayez de créer une slice de chaîne qui s'arrête au milieu +> d'un caractère encodé sur plusieurs octets, votre programme va se fermer avec +> une erreur. Afin de simplifier l'explication des slices de chaînes, nous +> utiliserons uniquement l'ASCII dans cette section ; nous verrons la gestion +> d'UTF-8 dans la section [“Stocker du texte encodé en UTF-8 avec les chaînes de +> caractères”][strings] du chapitre 8. -Maintenant que nous savons tout cela, essayons de ré-écrire `premier_mot` pour -retourner un découpage. Le type pour les “découpages de chaînes de caractères” +Maintenant que nous savons tout cela, essayons de réécrire `premier_mot` pour +qu'il retourne une slice. Le type pour les slices de chaînes de caractères s'écrit `&str` : Nous récupérons l'indice de la fin du mot de la même façon que nous l'avions -fait dans l'encart 4-7, en cherchant la première occurrence d'un espace. Lorsque -nous trouvons un espace, nous retournons un découpage de la chaîne de caractère -en utilisant le début de la chaîne de caractères et l'indice de l'espace comme -indices de début et fin. +fait dans l'encart 4-7, en cherchant la première occurrence d'une espace. +Lorsque nous trouvons une espace, nous retournons une slice de chaîne en +utilisant le début de la chaîne de caractères et l'indice de l'espace comme +indices de début et de fin respectivement. -Désormais quand nous appelons `premier_mot`, nous récupérons une seule valeur -qui est liée à la donnée de base. La valeur est construite avec une référence -vers le point de départ du découpage et avec le nombre d'éléments dans le -découpage. +Désormais, quand nous appelons `premier_mot`, nous récupérons une unique valeur +qui est liée à la donnée de base. La valeur se compose d'une référence vers le +point de départ de la slice et du nombre d'éléments dans la slice. -Retourner un découpage fonctionnerait aussi pour une fonction `second_mot` : +Retourner une slice fonctionnerait aussi pour une fonction `second_mot` : -Nous avons maintenant une API simple qui est bien plus difficile à perturber, +Nous avons maintenant une API simple qui est bien plus difficile à mal utiliser, puisque le compilateur va s'assurer que les références dans la `String` seront -toujours en vigueur. Souvenez-vous du bogue du programme de l'encart 4-8, +toujours en vigueur. Vous souvenez-vous du bogue du programme de l'encart 4-8, lorsque nous avions un indice vers la fin du premier mot mais qu'ensuite nous -avions vidé la chaîne de caractères et que notre index n'était plus valide ? Ce +avions vidé la chaîne de caractères et que notre indice n'était plus valide ? Ce code était logiquement incorrect, mais ne montrait pas immédiatement une erreur. Les problèmes apparaîtront plus tard si nous essayons d'utiliser l'indice du -premier mot avec une chaîne de caractère qui a été vidée. Les découpages rendent -ce bogue impossible et nous signale bien plus tôt que nous avons un problème -avec notre code. Utiliser la version avec le découpage de `premier_mot` va -afficher une erreur au moment de la compilation : +premier mot avec une chaîne de caractères qui a été vidée. Les slices rendent ce +bogue impossible et nous signalent bien plus tôt que nous avons un problème avec +notre code. Utiliser la version avec la slice de `premier_mot` va causer une +erreur de compilation : -Rappellons-nous que d'après les règles d'emprunt, si nous avons une référence +Rappelons-nous que d'après les règles d'emprunt, si nous avons une référence immuable vers quelque chose, nous ne pouvons pas avoir une référence mutable -en même temps. Etant donné que `clear` a besoin de modifier la `String`, il a +en même temps. Étant donné que `clear` a besoin de modifier la `String`, il a besoin d'une référence mutable. Rust interdit cette situation, et la compilation échoue. Non seulement Rust a simplifié l'utilisation de notre API, mais il a aussi éliminé une catégorie entière d'erreurs au moment de la compilation ! @@ -710,22 +693,16 @@ aussi éliminé une catégorie entière d'erreurs au moment de la compilation ! #### String Literals Are Slices --> -#### Les chaînes de caractères pures sont des découpages +#### Les littéraux de chaîne de caractères sont aussi des slices -Rappellez-vous lorsque nous avons appris que les chaînes de caractères pures -étaient enregistrées dans le binaire. Maintenant que nous connaissons les -découpages, nous pouvons désormais comprendre les chaînes de caractères pures. - - +Rappelez-vous lorsque nous avons appris que les littéraux de chaîne de +caractères étaient enregistrés dans le binaire. Maintenant que nous connaissons +les slices, nous pouvons désormais comprendre les littéraux de chaîne. ```rust let s = "Hello, world!"; @@ -737,24 +714,23 @@ the binary. This is also why string literals are immutable; `&str` is an immutable reference. --> -Ici, le type de `s` est un `&str` : c'est un découpage qui pointe vers un -endroit précis du binaire. C'est aussi la raison pour laquelle les chaînes de -caractères pures sont immuables; `&str` est une référence immuable. +Ici, le type de `s` est un `&str` : c'est une slice qui pointe vers un endroit +précis du binaire. C'est aussi la raison pour laquelle les littéraux de chaîne +sont immuables ; `&str` est une référence immuable. -#### Les découpages de chaînes de caractères en paramètres +#### Les slices de chaînes de caractères en paramètres -Savoir que vous pouvez utiliser des découpages de chaînes de caractères pures et -des `String` nous invite à apporter une petite amélioration sur `premier_mot`, -dont voici sa signature : +Savoir que l'on peut utiliser des slices de littéraux et de `String` nous incite +à apporter une petite amélioration à `premier_mot`, dont voici la signature : -Un Rustacé plus expérimenté écrirait plutôt la signature de l'encart 4_9, car +Un Rustacé plus expérimenté écrirait plutôt la signature de l'encart 4-9, car cela nous permet d'utiliser la même fonction sur les `&String` et aussi les `&str` : @@ -792,7 +768,7 @@ a string slice for the type of the `s` parameter --> Encart 4-9 : Amélioration de la fonction `premier_mot` en -utilisant un découpage de chaîne de caractère comme type du paramètre `s` +utilisant une slice de chaîne de caractères comme type du paramètre `s` -Si nous avons un découpage de chaîne de caractères, nous pouvons lui donner -directement. Si nous avons une `String`, nous pouvons envoyer un découpage de -toute la `String`. Concevoir une fonction afin de prendre un découpage de chaîne -de caractères plutôt qu'une référence à une `String` rend notre API plus -générique et plus utile sans perdre aucune fonctionnalité : +Si nous avons une slice de chaîne, nous pouvons la passer en argument +directement. Si nous avons une `String`, nous pouvons envoyer une slice de toute +la `String`. Définir une fonction qui prend une slice de chaîne plutôt qu'une +référence à une `String` rend notre API plus générique et plus utile sans perdre +aucune fonctionnalité : -### Les autres découpages +### Les autres slices -Les découpages de chaînes de caractères, comme vous pouvez l'imaginer, sont -spécifiques aux chaînes de caractères. Mais il existe aussi un type plus -générique. Imaginons ce tableau de données : - - +Les slices de chaînes de caractères, comme vous pouvez l'imaginer, sont +spécifiques aux chaînes de caractères. Mais il existe aussi un type de slice +plus générique. Imaginons ce tableau de données : ```rust let a = [1, 2, 3, 4, 5]; @@ -904,23 +873,15 @@ Just as we might want to refer to a part of a string, we might want to refer to part of an array. We’d do so like this: --> -Comme nous pouvons nous référer à un échantillon d'une chaîne de caractères, +Tout comme nous pouvons nous référer à une partie d'une chaîne de caractères, nous pouvons nous référer à une partie d'un tableau. Nous pouvons le faire comme ceci : - - -```rust -let a = [1, 2, 3, 4, 5]; - -let decoupage = &a[1..3]; -``` -Ce découpage est de type `&[i32]`. Il fonctionne de la même manière que les -découpages de chaînes de caractères, en enregistrant une référence vers le -premier élément et une longueur. Vous réutiliserez ce type de découpage pour -toutes les autres types de collections. Nous aborderons ces collections en -détail quand lorsque nous verrons les vecteurs au chapitre 8. +Cette slice est de type `&[i32]`. Elle fonctionne de la même manière que les +slices de chaînes de caractères, en enregistrant une référence vers le premier +élément et une longueur. Vous utiliserez ce type de slice pour tous les autres +types de collections. Nous aborderons ces collections en détail quand nous +verrons les vecteurs au chapitre 8. -Les concepts de possession, d'emprunt, et les découpages garantissent la -sécurité de la mémoire dans les programmes Rust au moment de la compilation. Le -langage Rust vous donne le contrôle sur l'utilisation de la mémoire comme tous -les autres systèmes de langages de programmation, mais celui qui possède les -données nettoie automatiquement ces données quand il sort de la portée, et cela -vous permet de ne pas avoir à écrire et déboguer du code en plus pour avoir -cette fonctionnalité. +Les concepts de possession, d'emprunt et de slices garantissent la sécurité de +la mémoire dans les programmes Rust au moment de la compilation. Le langage Rust +vous donne le contrôle sur l'utilisation de la mémoire comme tous les autres +langages de programmation système, mais le fait que celui qui possède des +données nettoie automatiquement ces données quand il sort de la portée vous +permet de ne pas avoir à écrire et déboguer du code en plus pour avoir cette +fonctionnalité.