Comment obtenir un & dyn T à partir d'un Box <dyn T> [duplicate]

Jan 11 2021

J'essaie d'obtenir un à &dyn Tpartir de a Box<dyn T>, comme dans l'exemple suivant. Cependant, la compilation échoue.

trait MyTrait {
    
}

struct Foo;
impl MyTrait for Foo {}

fn main() {
    let b: Box<dyn MyTrait> = Box::new(Foo);
    let c: &dyn MyTrait = &b;
}

(https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=69c72904fbceae5b55470a878a441b7d)

Le message d'erreur est

error[E0277]: the trait bound `Box<dyn MyTrait>: MyTrait` is not satisfied
  --> src/main.rs:10:27
   |
10 |     let c: &dyn MyTrait = &b;
   |                           ^^ the trait `MyTrait` is not implemented for `Box<dyn MyTrait>`
   |
   = note: required for the cast to the object type `dyn MyTrait`

Il est clair que vous pouvez obtenir un &Tfichier Box<T>. Je ne comprends pas pourquoi vous ne pouvez pas obtenir &dyn Tun Box<dyn T>.

Réponses

2 kmdreko Jan 11 2021 at 07:22

Pour obtenir un à &dyn Tpartir de a Box<dyn T>, utilisez &*:

let c: &dyn MyTrait = &*b;

Le *est utilisé pour déréférencer la boîte dans son contenu ( dyn MyTrait) puis &est utilisé pour l'obtenir comme référence.


C'est aussi la "bonne" façon d'obtenir un fichier à &Foopartir d'un fichier Box<Foo>. La raison qui &bfonctionne avec les types concrets est que le Dereftrait permet &Box<T>d'être contraint à &T:

Si T implémente Deref <Target = U>, et x est une valeur de type T, alors:

  • Les valeurs de type & T sont forcées à des valeurs de type & U

La raison pour laquelle cela ne fonctionne pas pour les objets de trait est que cela &dyn MyTrait pourrait être valide &Box<...>et que la contrainte n'est pas tentée même si elle échoue.