Como obter um & dyn T de uma caixa <dyn T> [duplicar]

Jan 11 2021

Estou tentando obter um &dyn Tde a Box<dyn T>, como no exemplo a seguir. No entanto, ele não consegue compilar.

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)

A mensagem de erro é

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`

É claro que você pode obter um &Tde a Box<T>. Não entendo por que você não consegue obter um &dyn Tde a Box<dyn T>.

Respostas

2 kmdreko Jan 11 2021 at 07:22

Para obter um &dyn Tde a Box<dyn T>, use &*:

let c: &dyn MyTrait = &*b;

O *é usado para desreferenciar a caixa em seu conteúdo ( dyn MyTrait) e, em seguida, &é usado para obtê-lo como uma referência.


Essa também é a maneira "certa" de obter um &Foode a Box<Foo>. A razão que &bfunciona com tipos concretos é porque o Dereftraço permite &Box<T>ser coagido a &T:

Se T implementa Deref <Target = U>, e x é um valor do tipo T, então:

  • Valores do tipo & T são coagidos para valores do tipo & U

O motivo pelo qual isso não funciona para objetos de traço é que &dyn MyTrait pode ser válido &Box<...>e a coerção não é tentada mesmo se falhar.