web-dev-qa-db-ja.com

Vec <Box <dyn Trait >>をVec <Rc <RefCell <dyn Trait >>>に移動する方法

Vec<Box<dyn Trait>>を入力として使用し、その要素をVec<Rc<RefCell<dyn Trait>>>。それを行う最良の方法は何ですか?

私が試した:

use std::cell::RefCell;
use std::rc::Rc;

trait Trait {}

fn main() {
    let mut source: Vec<Box<dyn Trait>> = Vec::new();
    let mut dest: Vec<Rc<RefCell<dyn Trait>>> = Vec::new();

    for s in source {
        let d = Rc::new(RefCell::new(s.as_ref()));
        dest.Push(d);
    }
}

しかし、私はエラーを受け取りました:

error[E0277]: the trait bound `&dyn Trait: Trait` is not satisfied
  --> src/main.rs:12:19
   |
12 |         dest.Push(d);
   |                   ^ the trait `Trait` is not implemented for `&dyn Trait`
   |
   = note: required for the cast to the object type `dyn Trait`

実際に可能ですか、それとも入力タイプを変更する必要がありますか?

5
Nick

Traitを制御する場合の1つのオプションは、内部の実装を遅延させることで、Box<dyn Trait>に実装することです。

// We could implement Trait only for Box<dyn Trait>, but usually what you want
// is to implement it for all Boxes of things that are Trait instead
impl<T: ?Sized + Trait> Trait for Box<T> {}

fn pushes(dest: &mut Vec<Rc<RefCell<dyn Trait>>>, source: Vec<Box<dyn Trait>>) {
    for s in source {
        dest.Push(Rc::new(RefCell::new(s)));
    }
}

これは、すでにBoxedオブジェクトを2番目のポインター(Rc)の後ろにラップすることに注意してください。パフォーマンスに依存するアルゴリズムでdestを使用している場合は、1回ではなく2回逆参照する必要があります。 Box<T: Trait>を受け入れることができるようにコードを再構成できる場合、TBoxからRefCellに移動することにより、二重の間接参照を排除できます。

関連する質問

1
trentcl

_RefCell<dyn Trait>_は有効なタイプですが、 _RefCell<T>_ の宣言により_T: ?Sized_が許可されるため、現在、モジュールの外部から作成する方法はありません。 CoerceUnsized 以外、サイズ付きの値で開始する必要があります。

ただし、unsafeコードを使用して Cell または UnsafeCell に変換できるはずです。 #[repr(transparent)]

1
Solomon Ucko