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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Rust Discussion :

Question sur le déréférencement


Sujet :

Rust

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Par défaut Question sur le déréférencement
    Bonjour,

    J'essaye d'apprendre le langage Rust. Je suis en train de faire les exercices rustlings (https://github.com/rust-lang/rustlings).
    J'en suis à l'exercice vecs2.rs (exercice sur les vecteurs)

    Dans la boucle, apparemment il faut déréférencer la variable "element" pour pouvoir l'utiliser. Je ne comprend pas pourquoi vu que des fois on a pas besoin de faire ça (exemple dans mon deuxième bout de code ci dessous).
    Question subsidiaire : Laquelle de ces deux boucles est la plus correcte ? celle avec l'appel à iter_mut ou l'autre ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
        for element in v.iter_mut() {
            *element *= 2;
        }
     
        /*for element in &mut v {
            *element *= 2;
        }*/
     
        v
    }

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    fn main() {
        let truc = String::from ("test");
        toto(&truc);
    }
    
    fn toto(param: &String) {
        println!("{}", param); // <-- Ca fonctionne avec ou sans le caractère * comment ca ce fait ?
    }

  2. #2
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Bonjour,

    Citation Envoyé par bombseb Voir le message
    Dans la boucle, apparemment il faut déréférencer la variable "element" pour pouvoir l'utiliser. Je ne comprend pas pourquoi vu que des fois on a pas besoin de faire ça (exemple dans mon deuxième bout de code ci dessous).

    […]

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    fn toto(param: &String) {
        println!("{}", param); // <-- Ca fonctionne avec ou sans le caractère * comment ca ce fait ?
    }
    println!("{}", expression) fonctionne avec toute expression dont le type implémente le trait Display.

    String implémente le trait Display : https://doc.rust-lang.org/std/fmt/tr...lay-for-String
    Or, *param (avec l'étoile) est de type String, donc il est affichable.

    Pour tout type T qui implémente Display, &T implémente Display aussi. Ce n'est pas vrai pour tous les traits. Cela peut être codé spécifiquement pour n'importe quel trait et c'est le cas de Display : https://doc.rust-lang.org/std/fmt/tr...splay-for-%26T
    Le vrai code fait appel à une macro, mais il équivaut à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    impl<T: ?Sized + Display> Display for &T {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result { Display::fmt(&**self, f) }
    }
    Or, String implémente Display, donc &String implémente Display.
    Or, param (sans l'étoile) est de type &String, donc il est affichable.

    Cela dit, la majorité des cas où du code Rust fonctionne sans déréférencer explicitement vient d'une autre règle. Quand on utilise la syntaxe de l'appel d'une méthode (object.method(arguments)), si l'objet est une référence et que le compilateur ne trouve pas immédiatement quelle méthode appeler, il va essayer de déréférencer jusqu'à ce qu'il trouve.
    La vraie règle est plus compliquée. Elle est décrite dans The Rust Reference, dans la page Method-call expressions.

    Citation Envoyé par bombseb Voir le message
    Question subsidiaire : Laquelle de ces deux boucles est la plus correcte ? celle avec l'appel à iter_mut ou l'autre ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
        for element in v.iter_mut() {
            *element *= 2;
        }
     
        /*for element in &mut v {
            *element *= 2;
        }*/
     
        v
    }
    La réponse courte, c'est que c'est pareil.

    Je peux détailler les règles sous-jacentes, mais ce sera un peu compliqué en début d'apprentissage.

    On peut faire une boucle for sur tout type qui implémente le trait IntoIterator. for element in x appelle une fois x.into_iter() qui est un itérateur (c'est-à-dire qui implémente le trait Iterator). Sur cet itérateur, la méthode next est appelée avant chaque itération de la boucle.
    La règle précise sur comment marche la boucle for est définie ici : https://doc.rust-lang.org/reference/...iterator-loops

    On peut itérer sur v.iter_mut() qui est déjà un itérateur, car v.iter_mut().into_iter() équivaut à v.iter_mut(). Plus généralement, tout type qui implémente le trait Iterator implémente aussi IntoIterator et alors into_iter est une fonction identité : https://doc.rust-lang.org/std/iter/t...Iterator-for-I

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    impl<I: Iterator> IntoIterator for I {
        type Item = I::Item;
        type IntoIter = I;
     
        #[inline]
        fn into_iter(self) -> I {
            self
        }
    }
    Dans ta boucle en commentaire, &mut v est une référence muable vers un vecteur, ce qui est un type qui implémente aussi IntoIterator : https://doc.rust-lang.org/std/vec/st...+Vec%3CT,+A%3E
    et la méthode into_iter correspondante appelle en fait iter_mut.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
        type Item = &'a mut T;
        type IntoIter = slice::IterMut<'a, T>;
     
        fn into_iter(self) -> Self::IntoIter {
            self.iter_mut()
        }
    }

  3. #3
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Par défaut
    oulala compliqué tout ca....

    Merci à toi d'avoir pris le temps de me répondre, on va dire que c'est résolu

    Je vais essayer de digérer tout ca...

  4. #4
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Bonjour,


    Citation Envoyé par bombseb Voir le message
    Bonjour,
    .......
    Dans la boucle, apparemment il faut déréférencer la variable "element" pour pouvoir l'utiliser. Je ne comprend pas pourquoi vu que des fois on a pas besoin de faire ça (exemple dans mon deuxième bout de code ci dessous).
    Question subsidiaire : Laquelle de ces deux boucles est la plus correcte ? celle avec l'appel à iter_mut ou l'autre ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    fn toto(param: &String) {
        println!("{}", param); // <-- Ca fonctionne avec ou sans le caractère * comment ca ce fait ?
    }


    Effectivement, vous devez déréférencer la variable élément dans la boucle for car élément est une référence mutable à l'élément vectoriel (éléments du vecteur &mut i32). La méthode que vous avez utiliser iter_mut() du vecteur retourne une itération sur les références mutables aux éléments. Ainsi donc à chaque tour de boucle on a une référence &mut i32 qu'il faut déréférencer avec *element pour pouvoir modifier sa valeur directement. Sans le *, on modifierait juste la référence et pas la valeur réelle dans le vecteur.

    Dans votre fonction toto la variable param est déjà une référence &String, donc il n'y a pas besoin de déréférencer pour l'utiliser dans println!. Car println! accepte directement les références en paramètre ce dont @Pyramidev a essayer de vous expliquer. En résumé: Quand on a une référence, pas besoin de déréférencer pour l'utiliser comme paramètre de fonction et aussi quand on a une référence mutable dans une boucle for, il faut déréférencer pour modifier la valeur réelle.
    pour les raison suivantes :

    • La fonction déclare le paramètre avec un type de référence. Ainsi donc, à l'intérieur de la fonction, ce paramètre est déjà une référence, pas besoin de la déréférencer à nouveau pour l'utiliser.
    • Quand on a une référence mutable dans une boucle for: La boucle for renvoie à chaque tour une référence mutable (&mut T) sur l'élément. Mais ça reste une référence, pas la valeur de base. Donc pour modifier la valeur réelle dans le vecteur / de la référence du vecteur, slice, etc. Il faut déréférencer avec * la référence renvoyée par le for pour avoir un accès direct à la valeur mutable. Sans le déréférencement, on ne ferait que modifier la référence elle-même (qui est une copie) et pas la valeur de base dans le vecteur.

    à bientôt.

  5. #5
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Par défaut
    Hello, merci pour vos éclaircissements je vais tester tout ca...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [debutant] Questions sur 1 futur projet
    Par cyrull22 dans le forum XML/XSL et SOAP
    Réponses: 3
    Dernier message: 28/04/2003, 21h49
  2. Quelques questions sur le TWebBrowser...
    Par CorO dans le forum Web & réseau
    Réponses: 3
    Dernier message: 17/01/2003, 21h23
  3. Question sur les handles et les couleurs...
    Par MrDuChnok dans le forum C++Builder
    Réponses: 7
    Dernier message: 29/10/2002, 08h45
  4. Réponses: 2
    Dernier message: 11/08/2002, 21h27
  5. question sur les message box !
    Par krown dans le forum Langage
    Réponses: 7
    Dernier message: 02/08/2002, 16h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo