Come ottenere un & dyn T da una scatola <dyn T> [duplicato]

Jan 11 2021

Sto cercando di ottenere un &dyn Tda a Box<dyn T>, come nell'esempio seguente. Tuttavia, non riesce a compilare.

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)

Il messaggio di errore è

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`

È chiaro che puoi ottenere un &Tda a Box<T>. Non capisco perché non puoi ottenere un &dyn Tda a Box<dyn T>.

Risposte

2 kmdreko Jan 11 2021 at 07:22

Per ottenere un &dyn Tda a Box<dyn T>, usa &*:

let c: &dyn MyTrait = &*b;

La *viene utilizzato per Deref la scatola nel suo contenuto ( dyn MyTrait) e quindi &viene utilizzato per ottenere come riferimento.


Questo è anche il modo "giusto" per ottenere un &Fooda a Box<Foo>. Il motivo per cui &bfunziona con i tipi concreti è perché il Dereftratto consente &Box<T>di essere costretti a &T:

Se T implementa Deref <Target = U> e x è un valore di tipo T, allora:

  • I valori di tipo & T sono obbligati a valori di tipo & U

Il motivo per cui non funziona per gli oggetti tratto è che &dyn MyTrait potrebbe essere valido &Box<...>e la coercizione non viene tentata anche se fallisce.