IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ sur la programmation en langage RustConsultez toutes les FAQ

Nombre d'auteurs : 1, nombre de questions : 95, dernière mise à jour : 21 juillet 2018  Ajouter une question

 

Cette FAQ a été réalisée pour répondre aux questions les plus fréquemment posées sur la programmation en langage Rust. Nous vous recommandons de la consulter avant de poser vos questions sur le forum Rust.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle contient sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci.

Toute nouvelle question/réponse est la bienvenue, vous pouvez proposer vos questions réponses par e-mail (voir le lien en bas de page) au(x) responsable(s) de la rubrique Rust ou mieux en postant votre proposition à la publication.
Vous pouvez participer à l'amélioration des questions réponses en postant directement dans cette FAQ. Une validation par le(s) responsable(s) de la rubrique Rust sera requise avant que vos contributions ne soient visibles.

Sur ce, nous vous souhaitons une bonne lecture.

SommaireLangageQuestions générales (50)
précédent sommaire suivant
 

La déclaration d'une variable en Rust se fait par le biais du mot-clé let, permettant ainsi de différencier une assignation d'une expression.

Vous pouvez bien entendu déclarer et initialiser plusieurs variables en même temps de cette manière :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
  
fn main()  
{ 
    let (foo, bar, baz) = (117, 42, "Hello world!"); 
    // ou 
    let foo = 117; 
    let bar = 42; 
    let baz = "Hello world!"; 
}

Mis à jour le 1er février 2017 Songbird

Il existe deux façons de faire :

  1. Préciser par le biais du caractère & (C-style).
  2. En utilisant le mot-clé ref comme ceci :

Code Rust : Sélectionner tout
1
2
3
4
5
6
fn main()  
{ 
    let foo: i32 = 117; 
    let ref bar = foo; 
    let baz = &foo; //idem 
}

Mis à jour le 1er février 2017 Songbird

Non.

Bien qu'il en donne l'air grâce à une syntaxe très aérée, Rust dispose d'un typage statique mais « optionnel » pour le développeur si ce dernier désire faire abstraction des types. Cependant il perdra, en toute logique, l'avantage de choisir la quantité de mémoire que sa ressource consommera.

Par exemple, vous ne pouvez pas faire ceci :

Code Rust : Sélectionner tout
1
2
3
4
fn main() { 
    let mut foo = 1; 
    foo = "Hello world !"; 
}

Le type ayant été fixé par la première donnée, il n'est plus possible de changer en cours de route.

Mis à jour le 21 novembre 2016 Songbird

Pour les types primitifs, il existe deux manières de typer une variable :

Code Rust : Sélectionner tout
1
2
3
4
fn main()  
{ 
    let foo: i32 = 117; 
}
Code Rust : Sélectionner tout
1
2
3
4
fn main()  
{ 
    let bar = 117i32; 
}

Mis à jour le 1er février 2017 Songbird

&str est un type immuable représentant une chaîne de caractères tandis que String est un wrapper mutable au-dessus de ce dernier.

Code Rust : Sélectionner tout
1
2
3
4
5
6
fn main() { 
    let foo: &str = "Hello world!"; // ça fonctionne 
    let bar: String = foo; // erreur 
    let baz: String = foo.to_owned(); // Ok ! 
    let baz: String = foo.to_string(); // Ok ! (équivalent de la ligne du dessus) 
}

Mis à jour le 1er février 2017 Songbird

La question pourrait paraître évidente dans d'autres langages, toutefois, après avoir écrit quelque chose de ce style :

Code Rust : Sélectionner tout
1
2
3
fn main() { 
    let foo: String = "Hello world!"; 
}

Le compilateur vous a renvoyé cette erreur :

Code : Sélectionner tout
1
2
3
  |> 
4 |>    let foo: String = "Hello world!"; 
  |>                      ^^^^^^^^^^^^^^ expected struct `std::string::String`, found &-ptr
Il se trouve que la structure String est un wrapper.

Vous vous retrouvez donc à typer votre variable pour accueillir une instance de la structure String alors que vous créez une chaîne de caractères primitive.

Pour remédier au problème (si vous souhaitez malgré tout utiliser le wrapper), vous pouvez convertir une chaîne de caractères de type &str grâce à la fonction String::from() :

Code Rust : Sélectionner tout
1
2
3
4
5
fn main() { 
    let foo: String = String::from("Hello world!"); 
    // ou 
    let foo: &str = "Hello world!"; 
}

Ou encore avec les méthodes to_owned et to_string (à préférer à la méthode from qui est un peu plus générale et donc plus lente) :

Code Rust : Sélectionner tout
1
2
3
4
fn main() { 
    let foo = "Hello world!".to_owned(); 
    let foo = "Hello world!".to_string(); 
}

Mis à jour le 21 novembre 2016 Songbird

Actuellement(1er février 2017), la version stable la plus récente est la 1.14.0.

Les versions antérieures à la 1.13.0 contenant des régressions, je vous conseille d'utiliser la version la plus récente proposée.

Mis à jour le 1er février 2017 Songbird

Rust propose l'encapsulation qui est un concept objet. On peut donc dire que Rust est orienté objet. Toutefois, l'encapsulation s'effectue à l'échelle d'un module et non d'une classe/structure comme on pourrait le remarquer en Java/C#.

Il dispose d'un aspect de la POO, de prime abord, assez primitif; Rust permet de bénéficier du polymorphisme grâce aux « traits » qui pourraient être comparées aux interfaces Java/C#.

Cependant, le langage ne supporte pas l'héritage multiple (ni l'héritage simple) entre les structures, comme il serait possible de le faire avec des classes, bien qu'il soit possible de le faire avec des traits.

Par conséquent, Rust est orienté objet, puisqu'il possède plusieurs parties de ce paradigme, mais n'est pas un langage objet pur.

Mis à jour le 28 novembre 2016 Songbird

Un trait pourrait être comparé aux interfaces que l'on peut retrouver dans la plupart des langages orientés objet (Java, C#…).
Les traits vous permettent de déclarer des fonctions abstraites/virtuelles pour ensuite les implémenter au sein d'une structure grâce au mot-clé impl comme ceci :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
trait Greeter 
{ 
    fn greetings(&self); 
} 
  
struct Person; 
  
impl Greeter for Person 
{ 
    fn greetings(&self) 
    { 
        println!("Hello, my friends!"); 
    } 
} 
  
fn main() 
{ 
    let person = Person; 
    person.greetings(); 
}

Pour aller au plus simple, un trait vous permet d'écrire un ensemble de fonctions qu'un objet est obligé d'implémenter lorsqu'il hérite de ce trait.

Mis à jour le 21 novembre 2016 Songbird

Rust ne supporte pas la surcharge des fonctions.

Le langage repose sur le « Builder Pattern » qui consiste à concevoir des « fabriques/factories » chargées de générer l'objet désiré.

Vous pouvez retrouver quelques explications à propos de ce design pattern ici ou encore ici.

Mis à jour le 21 novembre 2016 Songbird

Il n'est pas possible de déclarer des paramètres optionnels avec Rust dans sa version actuelle.

Toutefois, il est toujours possible d'user de macros pour capturer différentes expressions et ainsi adapter votre code en fonction de la situation.

Le langage repose sur le « Builder Pattern » qui consiste à concevoir des « fabriques/factories » chargées de générer l'objet désiré.

Vous pouvez retrouver quelques explications à propos de ce design pattern ici ou encore ici.

Mis à jour le 28 novembre 2016 Songbird

Un tableau dans sa forme la plus primitive se déclare comme ceci :

Code Rust : Sélectionner tout
let foo: [i32; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

Note: la taille du tableau doit être explicite, sous peine de recevoir une erreur de la part du compilateur.

Mis à jour le 1er février 2017 Songbird

Contrairement à ce que l'on pourrait croire, le mot-clé super ne représente pas une référence vers l'instance courante d'une classe mère, mais représente seulement le « scope » supérieur (dans un module).

Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
mod mon_module 
{ 
    pub fn ma_fonction() 
    { 
        println!("Scope supérieur"); 
    } 
    pub mod fils 
    { 
        pub fn fonction_enfant() 
        { 
            super::ma_fonction(); 
        } 
    } 
    pub mod fille 
    { 
        pub fn fonction_enfant() 
        { 
            super::ma_fonction(); 
        } 
    } 
} 
  
fn main() 
{ 
    mon_module::fils::fonction_enfant(); 
    mon_module::fille::fonction_enfant(); 
}

Mis à jour le 9 octobre 2016 Songbird

Le mot-clé self est l'instance courante de votre type.
Il est souvent rencontré :

  • lorsqu'une fonction virtuelle/abstraite est implémentée au sein d'une structure (et qu'elle doit être dépendante d'une instance de cette dernière) ;
  • lorsque le développeur doit utiliser une fonction dans le module courant ;



Exemple:

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
trait My_Trait 
{ 
    fn my_func(&self); 
} 
  
mod My_Mod 
{ 
    fn foo() 
    { 
        self::bar(); 
    } 
  
    fn bar() 
    { 
  
    } 
}

Il sert aussi à désigner le module courant lors d'un import. Par exemple :

Code Rust : Sélectionner tout
1
2
3
use std::io::{self, File}; 
  
// maintenant on peut utiliser File mais aussi io !

Mis à jour le 28 novembre 2016 Songbird

Le mot-clé use permet de gérer les imports d'autres modules.

Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
extern crate mon_package; 
  
use mon_package::mon_module::ma_fonction; 
  
fn main() 
{ 
    ma_fonction(); 
}

Autrement dit, toute structure composée de différentes ressources peut être exploitée par le mot-clé use.

Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
enum MonEnum { 
    Arg1, 
    Arg2, 
} 
  
fn main() { 
    use MonEnum::Arg1; // On importe le variant Arg1 de l'enum MonEnum ici. 
  
    let instance = Arg1; // Et on l'utilise directement ici. 
    // Plus la peine d'expliciter d'où provient l'instance Arg1 comme ceci : 
    let instance = MonEnum::Arg1; 
}

Il permet aussi de réexporter des modules vers le scope supérieur. Prenons par exemple un projet possédant cette hiérarchie :

Code text : Sélectionner tout
1
2
3
4
5
6
7
8
9
src 
 ├─── fichier.rs 
 ├─── video 
 |      ├──── video.rs 
 |      ├──── mod.rs 
 | 
 ├─── audio 
        ├──── audio.rs 
        ├──── mod.rs

Pour pouvoir accéder aux items présents dans audio.rs et video.rs, vous allez devoir les rendre visibles dans les niveaux supérieurs en les réexportant comme ceci :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
// dans video/mod.rs 
pub use self::video::{Video, une_fonction}; 
  
mod video; 
  
// dans audio/mod.rs 
pub use self::audio::{Audio, une_autre_fonction}; 
  
mod audio;

Dans fichier.rs, vous pourrez désormais faire :

Code Rust : Sélectionner tout
1
2
use Audio; 
use Video;

Mis à jour le 1er février 2017 Songbird

Le mot-clé pub peut être utilisé dans trois contextes différents :

1. Au sein [et sur] des modules;
2. Au sein [et sur] des traits;
3. Au sein [et sur] des structures.

Dans un premier temps, qu'il soit utilisé sur des modules, traits, ou structures, il aura toujours la même fonction : rendre publique l'objet concerné.

Exemple :

Code text : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
├── Cargo.lock 
├── Cargo.toml 
├── src 
│   ├── lib.rs 
│   └── main.rs 
└── target 
    └── debug 
        ├── build 
        ├── deps 
        ├── examples 
        ├── libmon_projet.rlib 
        ├── mon_projet 
        └── native
Code Rust : Sélectionner tout
1
2
3
4
5
6
7
pub mod ma_lib { //la module représentant ma bibliothèque 
    pub mod mon_module { // un module lambda 
        pub fn ma_fonction() { //ma fonction 
            println!("Hi there !"); 
        } 
    } 
}


Code Rust : Sélectionner tout
1
2
3
4
5
6
7
extern crate mon_projet; 
  
use mon_projet::ma_lib::mon_module::ma_fonction; 
  
fn main() { 
    ma_fonction(); 
}


Renvoie :

Code text : Sélectionner tout
Hi there !

mon_projet est le nom porté par votre projet dans le manifest Cargo.toml.

Pour cet exemple, voici le manifest rédigé :

Code toml : Sélectionner tout
1
2
3
4
5
6
[package] 
name = "mon_projet" 
version = "0.1.0" 
authors = ["Songbird0 <chaacygg@gmail.com>"] 
 
[dependencies]


Comment faire une méthode statique ?

Tout dépend de la présence de self/&self/&mut self en premier argument. Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct A; 
  
impl A { 
    fn foo() { // ceci est une méthode statique 
    } 
  
    fn foo1(arg: i32) { // ceci est une méthode statique 
    } 
  
    fn foo2(&self) { // ceci n'est pas une méthode statique 
    } 
  
    fn foo3(self) { // ceci n'est pas une méthode statique non plus 
    } 
  
    fn foo4(&self, arg: i32) { // ceci n'est pas non plus une méthode statique 
    } 
}

Mis à jour le 28 novembre 2016 Songbird

Les mot-clés extern crate permettent d'importer un paquet entier de modules dans le fichier courant.
Le principe est simple, il vous suffit de créer en premier lieu un projet en mode « bibliothèque » pour réunir tous les modules que vous créerez, de créer un fichier qui accueillera le point d'entrée de votre programme, puis d'importer votre paquet.

Bien entendu, si vous souhaitez importer un paquet qui n'est pas de vous, il vous faudra l'inscrire dans votre manifest.

Mis à jour le 12 septembre 2016 Songbird

Voir aussi :
Pour voir un exemple de création de paquet, vous pouvez vous rendre à la Q/R : « A quoi sert le mot-clé pub ? »
Comment installer de nouvelles bibliothèques ?

Le mot-clé mod vous permet d'importer ou de déclarer un module. Il est important de noter que les fichiers sont considérés comme des modules. Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
mod a { // Ici on crée un module. 
    fn foo() {} 
} 
  
mod nom_du_fichier; // Ici on importe le fichier "nom_du_fichier.rs".

Mis à jour le 1er février 2017 Songbird

Il vous permet de réunir plusieurs objets (structures, traits, fonctions, d'autres modules…) dans un même fichier puis de les réutiliser à plusieurs endroits dans votre programme.

Mis à jour le 1er février 2017 Songbird

Voici comment créer un module :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
mod A { 
    fn votre_fonction() {} 
    fn une_autre_fonction() {} 
  
    mod B { 
        struct C; 
        trait D {} 
    } 
}

Mis à jour le 1er février 2017 Songbird

Le mot-clé type permet de créer des alias et ainsi réduire la taille des types personnalisés (ou primitifs).

Voici un exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
use std::collections::HashMap; 
  
type MonDico = HashMap<String, i32>; // On met un alias sur la HashMap. 
  
fn main() { 
    let x = MonDico::new(); // Plus besoin de s'embêter avec le long nom et ses paramètres de types ! 
}

Mis à jour le 28 novembre 2016 Songbird

Pour exécuter l'exemple de la Q/R, vous pouvez vous rendre ici.
Retrouvez des explications ici.
Explications de la documentation officielle.

Le mot-clé loop sert à créer des boucles infinies. Pour faire simple, c'est un sucre syntaxique qui permet de remplacer le fameux :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
while(true) { 
  
} 
  
// ou 
  
for(;;) { 
  
}

Préférez donc cette syntaxe :

Code Rust : Sélectionner tout
1
2
3
loop { 
  
}

Mis à jour le 28 novembre 2016 Songbird

Le mot-clé where permet de filtrer les objets passés en paramètres dans une fonction générique, par exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
trait Soldier{} 
trait Citizen{} 
  
struct A; 
struct B; 
  
impl Soldier for A{} 
  
fn foo<T>(test: T) -> T where T: Soldier 
{ 
    return test; 
} 
  
fn main() 
{ 
    let soldier : A = A; 
    let citizen : B = B; 
    foo(soldier); 
    foo(citizen); //error: the trait bound `B: Soldier` is not satisfied 
}

Mis à jour le 21 juillet 2018 Songbird

Le mot-clé unsafe permet, comme son nom l'indique, de casser certaines règles natives de Rust pour effectuer des opérations « à risque ».

En pratique, le mot-clé unsafe permet une manipulation de la mémoire plus approfondie, plus directe, mais aussi plus compliquée, puisque le langage n'applique pas certaines règles.

Pour faire simple : utilisez unsafe aussi peu que possible.

Exemple d'utilisation d'unsafe :

Code Rust : Sélectionner tout
1
2
3
let x: i32 = &0; 
let ptr = x as *const i32; 
unsafe { *ptr; } // on tente d'accéder à l'élément pointé par le pointeur, ce qui est hautement "unsafe"

Mis à jour le 28 novembre 2016 Songbird

Trois règles, et seulement trois, sont brisées dans les blocs (et fonctions) unsafe :

  1. L'accès et la modification d'une variable globale (statique) muable sont autorisés ;
  2. Il est possible de déréférencer un pointeur (non nul, donc) ;
  3. Il est possible de faire à une fonction non sûre.

Mis à jour le 21 juillet 2018 Songbird

Pour en retrouver une liste exhaustive, rendez-vous à la section dédiée.

Mis à jour le 15 octobre 2016 Songbird

En Rust, pour déclarer une fonction, il faut utiliser le mot-clé fn :

Code Rust : Sélectionner tout
1
2
3
4
fn ma_fonction() 
{ 
  
}

Pour spécifier le type renvoyé par la fonction, vous devez utiliser le token -> + le type de votre choix.

Code Rust : Sélectionner tout
1
2
3
4
fn ma_fonction() -> Foo 
{ 
    Foo 
}

Mis à jour le 21 juillet 2018 Songbird

Le mot-clé match nous permet d'implémenter le pattern matching.

Ainsi, il est possible de comparer une entrée à plusieurs tokens constants et agir en conséquence. Le pattern matching est considéré comme un test exhaustif, car, quoi qu'il arrive, il fera en sorte de couvrir tous les cas de figure qu'on lui propose.

Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
let foo: i32 = 117; 
  
match foo { 
    117 => println!("foo vaut 117 !"), 
    _ => println!("You know nothing, John."), // s'efforcera de trouver une réponse 
}

Jusqu'ici, il semblerait que le mot-clé match ne soit pas capable de faire preuve de plus de souplesse qu'un switch, ce qui est bien entendu le contraire ! Vous pouvez par-exemple matcher sur un ensemble de valeurs :

Code Rust : Sélectionner tout
1
2
3
4
5
6
let foo: i32 = 117; 
  
match foo { 
    100...120 => println!("foo est entre 100 et 120 !"), 
    x => println!("You know nothing, John. (foo vaut {})", x), // s'efforcera de trouver une réponse 
}

Le pattern matching est très puissant, n'hésitez pas à en user et en abuser !

Mis à jour le 28 novembre 2016 Songbird

Voir aussi :
Vous pouvez exécuter l'exemple ici.
Vous pouvez retrouver une source abordant le pattern matching (avec plusieurs exemples).
Partie de la documentation officielle abordant l'implémentation du pattern matching.

Le mot-clé ref est une alternative au caractère spécial & pour expliciter le renvoi d'une référence d'un objet :

Code Rust : Sélectionner tout
1
2
3
4
5
6
struct A ; 
fn main() 
{ 
    let foo : A = A ; 
    let bar : &A = &foo ; // ou let ref bar = foo ; 
}

Il permet aussi de dire explicitement qu'une valeur ne doit pas être "bougée"/move dans certains contextes.

Mis à jour le 28 novembre 2016 Songbird

Le mot-clé mut permet de rendre l'une de vos variables mutable lors de sa déclaration.

Code Rust : Sélectionner tout
1
2
3
4
let mut foo : i32 = 0 ; 
let bar : i32 = 1 ; 
foo = 1 ; 
bar = 2 ; // erreur

Mis à jour le 21 juillet 2018 Songbird

Il se peut que vous ayez omis la particularité de Rust : tout est immuable par défaut.
Pour permettre à une variable de modifier son contenu, il vous faudra utiliser le mot-clé mut.

Mis à jour le 28 novembre 2016 Songbird

Une macro est ce que l'on peut appeler vulgairement une fonction très puissante.

Grâce aux macros, nous pouvons capturer plusieurs groupes d'expressions et ainsi écrire les instructions désirées selon chaque cas.

Pour grossir un peu le trait : les macros sont une extension du compilateur de Rust. Elles sont interprétées au moment de la compilation, pas pendant l'exécution de votre programme.

Mis à jour le 1er février 2017 Songbird

Pour utiliser une macro, il faut d'abord la déclarer en utilisant le mot-clé macro_rules!. (Attention, il ne doit pas y avoir d'espace(s) entre macro_rules et le point d'exclamation.)

Code Rust : Sélectionner tout
1
2
3
4
macro_rules! foo 
{ 
    () => (); 
}

Toutes les macros (y compris celle présentée ici) respectent une règle très importante : elles doivent toutes capturer au moins une expression pour être valides et compilées (en l'occurrence, la regex () => ();).

C'est donc cela, l'une des différences majeures entre une fonction/procédure et une macro : cette dernière est capable de capturer des expressions rationnelles, conserver en mémoire ce que désire le développeur, puis de les réutiliser dans le corps de l'une d'entre-elles.
Ces « super » fonctions demandent donc quelques notions liées aux expressions rationnelles pour vous permettre d'apprécier pleinement ce puissant mécanisme.

Voici un exemple très basique de macro :






Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/// **Attention**: 
///  
///Cette macro n'utilise qu'un seul type de spécificateur, mais il en existe beaucoup d'autres. 
macro_rules! foo 
{ 
    ($your_name:expr, $your_last_name:expr, $carriage_return: expr) => 
    { 
        if $carriage_return == true 
        { 
            println!("My name's {} {}.", $your_name, $your_last_name);  
        } 
        else { print!("My name's {} {}.", $your_name, $your_last_name); } 
    }; 
  
    ($your_name:expr, $your_last_name:expr) => 
    { 
        foo!($your_name, $your_last_name, false); 
    }; 
  
    ($your_name:expr) => 
    { 
        foo!($your_name, "", false); 
    }; 
} 
  
fn main() -> () 
{ 
    foo!("Song", "Bird", true); 
    foo!("Song", "Bird"); //pas de retour à la ligne 
    foo!("Song"); //là non plus 
}




Vous aurez certainement remarqué que les paramètres passés sont assez spéciaux ; au lieu d'avoir le nom de leur type après les deux points (« : »), il est écrit expr.
C'est ce que l'on appelle un « spécificateur » .

Mis à jour le 1er février 2017 Songbird

Les spécificateurs sont des types d'entrées supportés par les macros; Il faut noter toutefois que ces fameux types font abstraction de la nature de l'entrée. (e.g. que l'entrée soit une châine de caractères ou un entier importe peu)

Vous pouvez retrouver, ci-dessous, une traduction de chaque description des spécificateurs proposés par le langage:

- ident: un identifiant. e.g. x; foo.
- path: une représentation d'un chemin "package-style"(e.g. T::SpecialA, std::path::Path).
- expr: une expression (e.g. 2 + 2; if true { 1 } else { 2 }; f(42)).
- ty: Un type (e.g. i32, &T, Vec<(char, String)>).
- pat: Un modèle/pattern (e.g. Some(t); (17, 'a'); _).
- stmt: Une (et une seule) déclaraction (e.g. let some = 3).
- block: Une suite de déclarations enveloppée par des crochets et/ou une expression (e.g. {log(error, "hi"); return 12;}).
- item: Un objet (e.g. fn foo(){}; struct Bar;).
- meta: Un "meta objet", plus connu sous le nom d'attributs (e.g. cfg(target_os = "windows")).
- tt: Un token tree. Certainement le type le plus puissant de la liste, puisqu'il vous permet de soumettre tout ce qui existe dans la syntaxe du langage.

Mis à jour le 1er février 2017 Songbird

Le mot-clé usize permet de laisser le compilateur choisir la taille en mémoire d'un entier non-signé (selon l'architecture de la machine sur laquelle le programme sera exécuté).

Mis à jour le 1er février 2017 Songbird

Le mot-clé isize permet de laisser le compilateur choisir la taille en mémoire d'un entier signé (selon l'architecture de la machine sur laquelle le programme sera exécuté).

Mis à jour le 28 novembre 2016 Songbird

Rust dispose d'un outil de développement multifonction nommé Cargo.
Cargo est en premier lieu un gestionnaire de paquets (qui vous permet donc de télécharger des modules Rust développés par d'autres programmeurs), mais vous épaule également dans la gestion, la construction de vos projets, la création de vos manifests, etc.

Un groupe de Q/R a été créé sur cette FAQ présentant une liste non-exhaustive de commandes supportées par Cargo suivi d'un exemple d'utilisation (vous pourrez également retrouver des exemples dans le manuel officiel de l'outil ($ man cargo) :

Mis à jour le 24 octobre 2017 Songbird

Pour utiliser vos fonctions en dehors de votre module, il vous faudra utiliser le mot-clé pub.

Mis à jour le 15 octobre 2016 Songbird

Pour comparer deux objets avec Rust, vous pouvez implémenter le trait PartialEq que vous pourrez ensuite utiliser avec == ou la méthode eq.
Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
fn main() 
{ 
    let foo = 0 ; 
    let bar = 0 ; 
    let baz = foo.eq(&bar) ; //true 
    let bazz = "Hello world !"; 
    let bazzz = "Hello world !".to_string() ; 
    let bazzzz = bazz.eq(&bazzz) ; //true 
}

Mis à jour le 28 novembre 2016 Songbird

Le shadowing consiste à faire abstraction des identificateurs qui pourraient être identiques à ceux se trouvant dans un scope (« champ ») plus petit, ou étranger à celui des autres identificateurs dans l'absolu.

Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
fn main() -> () 
{ 
    let foo : &str = "Hello"; 
    { 
        let foo : &str = "world!"; 
        println!("{}", &foo); 
    } 
    println!("{}", &foo); 
}

La première déclaration de foo a été « éclipsée » par celle se trouvant dans le deuxième scope. Lorsque cette dernière a été détruite (ou simplement mise hors d'accès, dans ce cas), la première déclaration de foo a été de nouveau opérationnelle.

Résultat :

Code : Sélectionner tout
1
2
world! 
Hello

Mis à jour le 15 octobre 2016 Songbird

Avec Rust, il est possible d'effectuer une « déstructuration » sur certains types de données, mais qu'est-ce que cela signifie exactement ?

Grâce au pattern matching, il est possible de créer, donc, des « modèles » pour isoler une partie de la structure et ainsi vérifier si notre entrée correspond à nos attentes.

Une déstructuration peut se faire sur :

  • les listes;
  • les tuples;
  • les énumérations;
  • les structures.

Mis à jour le 28 novembre 2016 Songbird

Pour isoler une valeur contenue dans un tuple, il faut d'abord écrire son modèle pour savoir où le chercher.
Par exemple, en assumant que nous cherchons une suite de chiffres dans un ordre croissant, il est simple de déterminer si cette suite est dans le bon ordre ou non.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    let foo = ("one", "two", "three"); 
    let bar = ("two", "one", "three");  
  
    match bar 
    { 
        ("one", x, "three") => 
        { 
            if x == "two" 
            { 
                println!("tout est en ordre !"); 
            } 
        }, 
        _ => println!("on dirait qu'il y a un problème dans votre tuple..."), 
    }

Lorsque vous construisez un modèle de ce type, gardez bien en tête que la valeur la plus à gauche représentera toujours la première valeur du tuple, et la plus à droite représentera toujours la dernière valeur du tuple.

Rien ne vous empêche donc de faire ceci :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    let foo = ("one", "two", "three"); 
    let bar = ("two", "one", "three");  
  
    match foo 
    { 
        ("one", x, y) => 
        { 
            if (x, y) == ("two", "three") //on surveille plusieurs valeurs 
            { 
                println!("tout est en ordre !"); 
            } 
        }, 
        _ => println!("on dirait qu'il y a un problème dans votre tuple..."), 
    }

Mis à jour le 28 novembre 2016 Songbird

Le pattern matching vous donne la possibilité de « décortiquer » une énumération, vous permettant ainsi d'effectuer des tests complets.
Voici un exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
pub enum Enum 
{ 
    One, 
    Two, 
    Three, 
    Four, 
} 
  
fn foo(arg: Enum) -> () 
{ 
    match arg 
    { 
        Enum::One =>  
        { 
            println!("One"); 
        }, 
        Enum::Two => 
        { 
            println!("Two"); 
        }, 
        Enum::Three => 
        { 
            println!("Three"); 
        }, 
        Enum::Four => 
        { 
            println!("Four"); 
        }, 
    } 
} 
  
fn main() 
{ 
    let (bar, baz, bazz, bazzz) = (Enum::One, Enum::Two, Enum::Three, Enum::Four); 
  
    foo(bar); 
    foo(baz); 
    foo(bazz); 
    foo(bazzz); 
}

Mis à jour le 15 octobre 2016 Songbird

Tout d'abord, la question que nous pourrions nous poser est : en quoi consiste la destructuration sur une structure ?

L'idée est d'isoler, encore une fois, les propriétés qui nous intéressent.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A 
{ 
    x: String, 
    y: String, 
    z: String, 
} 
  
fn main() -> () 
{ 
    let foo = A { 
                    x: "Hello".to_string(), 
                    y: " ".to_string(), 
                    z: "world!".to_string(), 
                }; 
    let A {x: a, y: b, z: c} = foo; //on décortique les attributs de notre structure 
    println!("{}{}{}", a, b, c); //puis on les utilise dans de nouvelles variables 
}

Vous souhaiteriez omettre un attribut ? Pas de problèmes !

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
    let foo = A { 
                    x: "Hello".to_string(), 
                    y: " ".to_string(), 
                    z: "world!".to_string(), 
                }; 
    let A {x: a, y: b, ..} = foo; //on décortique les attributs de notre structure 
    println!("{}{}", a, b); //puis on les utilise dans de nouvelles variables


Vous pouvez également isoler ce style d'opération dans un scope plus petit (empêchant l'utilisation des variables temporaires en dehors de ce dernier) comme ceci :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
    let foo = A { 
                    x: "Hello".to_string(), 
                    y: " ".to_string(), 
                    z: "world!".to_string(), 
                }; 
    { 
        let A {x: a, y: b, z: c} = foo; //on décortique les attributs de notre structure 
        println!("{}{}{}", a, b, c); //puis on les utilise dans de nouvelles variables 
    } 
  
    //a,b et c ne pourront plus être utilisés à partir d'ici

Mis à jour le 15 octobre 2016 Songbird

La bibliothèque standard de Rust propose un(e) trait/ interface nommé(e) PartialEq composée de deux fonctions :

  1. fn eq(&self, other: &instance_de_la_meme_structure);;
  2. fn ne(&self, other: &instance_de_la_meme_structure);.


Attention
Comme il est stipulé dans la documentation officielle, vous n'êtes pas forcé d'implémenter les deux fonctions : ne() étant simplement le contraire de eq() et vice versa, il serait redondant de les implémenter dans la même structure.

Ci-dessous figure un exemple complet d'implémentation :






Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
struct Spartan<'a> 
{ 
  
    sid: i32,  
    name: &'a str 
  
} 
  
impl<'a> PartialEq for Spartan<'a> 
{ 
    fn eq(&self, other: &Spartan) -> bool 
    { 
        self.sid == other.sid 
    } 
} 
  
impl<'a> Spartan<'a> 
{ 
  
    pub fn new(sid: i32, name: &str) -> Spartan 
    { 
        Spartan 
        { 
            sid: sid, 
            name: name, 
        } 
    } 
} 
fn main() 
{ 
    let (foo , bar) = (Spartan::new(117, "John"), Spartan::new(062, "Jorge")); 
  
    if foo == bar  
    {  
        println!("foo equals bar");  
    }  
    else  
    {  
        println!("foo not equals bar");  
    } 
}



Mis à jour le 1er février 2017 Songbird

Il se pourrait que vous ayez omis d'utiliser une annotation : #[macro_use].
Cette dernière permet d'exporter toutes les macros qui doivent être publiques pour être utilisées à l'extérieur de la bibliothèque.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
#[macro_use] 
extern crate votre_lib; 
  
fn main() -> () 
{ 
 votre_macro!(); 
}

Si vous ne parvenez toujours pas à les utiliser, il est possible que vous ayez omis l'annotation #[macro_export] dans les modules comportant vos macros.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// dans le fichier lib.rs 
#[macro_use]//bien préciser que ce module utilise des macros 
pub mod votre_conteneur 
{ 
    #[macro_export] 
    macro_rules! foo 
    { 
        () => (); 
    } 
    #[macro_export] 
    macro_rules! bar 
    { 
        () => (); 
    } 
    #[macro_export] 
    macro_rules! baz 
    { 
        () => (); 
    } 
}

Si votre problème persiste, je vous invite à vous rendre sur les forums figurant dans la rubrique programmation pour obtenir de l'aide. Présentez clairement l'erreur que le compilateur vous renvoie dans votre post.

Mis à jour le 15 octobre 2016 Songbird

La combinaison des deux mot-clés permet d'assigner, de manière concise, du contenu à une variable.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn main() -> () 
{ 
    let foo : Option<String> = Some("Hello world!".to_string()); 
    let mut bar : bool = false; 
  
    if let Some(content) = foo // si la variable foo contient quelque chose... 
    { 
        bar = true; 
    } 
    else 
    { 
        println!("foo's content is None"); 
    } 
}

C'est un moyen simple et efficace d'assigner du contenu sans passer par le pattern matching.

Mis à jour le 28 novembre 2016 Songbird

La combinaison des deux mot-clés permet d'effectuer des tests concis et ainsi nous éviter de passer par le pattern matching lorsque cela n'est pas nécessaire. (while let peuvent s'avérer très utiles lorsqu'il faut tester à chaque itération si le fichier contient toujours quelque chose).

[Exemple de la documentation officielle]

Code Rust : Sélectionner tout
1
2
3
4
let mut v = vec![1, 3, 5, 7, 11]; 
while let Some(x) = v.pop() { 
    println!("{}", x); 
}

Mis à jour le 28 novembre 2016 Songbird

Le marqueur 'b' préfixant parfois une chaîne de caractères littérale permet de la convertir en une slice d'octets dont la longueur est égale à la somme de la taille (en octet) de chaque caractère composant la chaîne.

Prenons le caractère espagnol suivant: "ñ" qui est un caractère qui ne fait pas partie de la table ASCII et est codé sur 3 octets:

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
  
fn main() { 
    let foo: &'static str = "ñ"; // une string composée d'un seul caractère. 
    let bar: &'static [u8; 3] = b"\x00F1"; // la slice contient trois éléments (i.e. les trois octets que consomment "ñ"). 
    let baz: &'static str = "foo"; 
    let bang: &'static [u8; 3] = b"foo"; // contient trois éléments car chacun d'entre-eux  
    // n'est codé que sur un seul octet. 
}

Mis à jour le 23 octobre 2017 Songbird

Pour visualiser un exemple d'utilisation réel, vous pouvez vous rendre à la Q/R: Comment écrire à l'intérieur d'un fichier ?

Il existe autant de tuples que de possibilités de combinaisons entre les types. Chaque tuple est un type à part entière dont la signature sera différencier d'un autre (à condition que ce dernier ait une signature significativement différente).

Lecture d'un tuple

Comme il peut être le cas pour les tableaux primitifs, les éléments contenus par un tuple sont indexés de 0 à n-1n est égal au nombre d'éléments composant le tuple. En revanche, il faut utiliser la notation pointée pour accéder à l'élément voulu, au lieu de l'expression classique [N] des tableaux.

Code Rust : Sélectionner tout
1
2
3
4
5
fn main() { 
    let mut foo: (String,) = ("Hello,".to_owned(),); 
    // On récupère le premier élément. 
    foo.0.push_str(" world!"); 
}
Code Rust : Sélectionner tout
1
2
3
4
5
fn main() { 
    let mut foo: (String,) = ("Hello,".to_owned(),); 
    // error[E0608]: cannot index into a value of type `(std::string::String,)` 
    foo[0].push_str(" world!"); 
}

Modification des éléments du tuple

A l'instar des autres types de ressources, les éléments d'un tuple ne peuvent être modifiés que si ce dernier est mutable.
Sauf si l'un des éléments est explicitement défini comme mutable (par le biais d'une référence), les éléments hériteront des droits d'accès du tuple.

Code Rust : Sélectionner tout
1
2
3
4
5
fn main() { 
    let foo: (String,) = ("Hello,".to_owned(),); 
    // error[E0596]: cannot borrow field `foo.0` of immutable binding as mutable 
    foo.0.push_str(" world!"); 
}
Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  
fn main() { 
    let mut foo: (String,) = ("Hello,".to_owned(),); 
    foo.0.push_str(" world!"); 
  
    { 
        let bar: (&mut String,) = (&mut foo.0,); 
        bar.0.push_str("\nHello there!"); 
    } 
} 
  
// Displays: 
// Hello, world! 
// Hello there!

Mis à jour le 21 juillet 2018 Songbird

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2022 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.