Rust : à quoi sert le mot-clef dyn ?

quel est le rapport avec trait,box,error ?

a marqué ce sujet comme résolu.

dyn signifie dynamique. C’est utile pour définir qu’une fonction attend un type qui implémente un trait en particulier, peut importe la structure derrière qui l’implémente.

+2 -0

Salut,

Le trait en Rust est plus ou moins l’équivalent de l’interface, ou de la classe abstraite dans d’autres langages (un ensemble de méthodes et d’attributs qui peuvent être implémentées par les méthodes d’une structure, l’équivalent de ce qu’on appellerait les méthodes d’une classes dans d’autres langages).

Le mot-clef « dyn » en Rust est utilisé pour définir qu’une variable ou un argument de fonction correspond à un objet qui implémente un trait, sans forcément indiquer dans le code quel est le type de cet objet. Le type n’est donc connu qu’à l’exécution (donc « dynamiquement »).

Quand tu écris Box<dyn Error> pour par exemple désigner la valeur de retour d’une fonction dans son prototype, comme tu peux souvent avoir l’occasion de le faire vu que la nouvelle convention de gestions d’erreurs en Rust implique généralement de retourner éventuellement une erreur dans un Result<>, c’est que tu retournes une structure (par exemple std::io::Error) qui implémente le trait Error (alias std::err::Error), dont le type n’est pas connu à l’exécution (d’où le « dyn » - ça te permet de retourner plusieurs types d’erreurs différentes) et qui sera contenue dans un pointeur heap (d’où le « Box », alias std::boxed::Box).

Bonne journée,

Exemple de code:

trait Animal {
    fn marcher(&self);
}

struct Mouton {
    
}
impl Mouton {
    fn beler(&self) {
        println!("*Bêlement*");
    }
}
impl Animal for Mouton {
    fn marcher(&self) {
        println!("*Bruits de pas dans l'herbe*");
    }
}

struct Cheval {
    
}
impl Animal for Cheval {
    fn marcher(&self) {
        println!("*Bruits de pas sur la route*");
    }
}

fn faire_marcher_animal(animal: Box<dyn Animal>) {
    animal.marcher();
}

Je définis d’abord un trait Animal qui indique que les types implémentant le trait doivent implémenter une méthode fn marcher(&self);.

Je créé un type Mouton qui sait marcher et bêler, et un type Cheval qui sait marcher (tous deux implémentent le trait Animal).

Ensuite, je définis une fonction faire_marcher_animal qui prend un animal (n’importe lequel) et qui le fait marcher. Le type que j’indique ici est Box<dyn Animal>, cela indique que j’attends un pointeur heap (Box) qui fait référence à un objet implémentant le trait Animal.

Si mon argument n’était pas contenu dans un pointeur heap, je ne pourrais pas juste faire passer mon animal sur la stack car les types Mouton et Cheval ont potentiellement des structures mémoire de tailles différentes ; Rust ne devrait donc pas accepter que j’écrive juste dyn Animal.

Le fait que j’écrive dyn Animal indique que j’attends un objet qui implémente le trait Animal (donc qui implémente la méthode fn marcher(&self)). Néanmoins je ne peux pas être sûr que mon animal est un Mouton, je ne peux donc pas le faire bêler après le passage en argument.

Si je mettais Mouton ou bien Cheval à la place de dyn Animal, je pourrais le faire bêler dans le cas du Mouton, mais je ne pourrais pas alors accepter le Cheval (ou alors, il faudrait que je créé une enum qui puisse contenir à la fois Mouton et Cheval, et que j’extraie ensuite le Mouton ou le Cheval avec une construction match, mais dans ce cas le trait ne me sera plus utile..).

+2 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte