如何将 Rc<RefCell<Box<MyStruct>>> 传递给接受 Rc<RefCell<Box<dyn MyTrait>>> 的函数?

Dmi*_*rov 8 smart-pointers rust trait-objects

我最初在这里问过这个问题,但它被标记为重复,尽管在我看来它只重复了其中的一部分,所以我创建了一个更具体的问题:

考虑以下代码:

use std::rc::Rc;

trait MyTrait {
    fn trait_func(&self);
}

struct MyStruct1;

impl MyStruct1 {
    fn my_fn(&self) {
        // do something
    }
}

impl MyTrait for MyStruct1 {
    fn trait_func(&self) {
        // do something
    }
}

fn my_trait_fn(t: Rc<dyn MyTrait>) {
    t.trait_func();
}

fn main() {
    let my_str: Rc<MyStruct1> = Rc::new(MyStruct1);
    my_trait_fn(my_str.clone());
    my_str.my_fn();
}
Run Code Online (Sandbox Code Playgroud)

这段代码工作正常。现在我想更改 的定义trait_func以接受 a &mut self,但它不会像Rc仅适用于不可变数据那样工作。我使用的解决方案是包装MyTraitRefCell

use std::cell::RefCell;

fn my_trait_fn(t: Rc<RefCell<Box<dyn MyTrait>>>) {
    t.borrow_mut().trait_func();
}

fn main() {
    let my_str: Rc<RefCell<Box<MyStruct1>>> = Rc::new(RefCell::new(Box::new(MyStruct1)));
    my_trait_fn(my_str.clone());
    my_str.my_fn();
}
Run Code Online (Sandbox Code Playgroud)

当我编译它时,我收到一个错误:

use std::rc::Rc;

trait MyTrait {
    fn trait_func(&self);
}

struct MyStruct1;

impl MyStruct1 {
    fn my_fn(&self) {
        // do something
    }
}

impl MyTrait for MyStruct1 {
    fn trait_func(&self) {
        // do something
    }
}

fn my_trait_fn(t: Rc<dyn MyTrait>) {
    t.trait_func();
}

fn main() {
    let my_str: Rc<MyStruct1> = Rc::new(MyStruct1);
    my_trait_fn(my_str.clone());
    my_str.my_fn();
}
Run Code Online (Sandbox Code Playgroud)

解决这个问题的最佳方法是什么?

Chr*_*gan 5

(这个答案的较旧版本基本上建议克隆底层结构并将其放入一个新Rc<RefCell<Box<MyTrait>>对象中;这在稳定的 Rust 上当时是必要的,但因为在那之后不久,Rc<RefCell<MyStruct>>将强制执行而Rc<RefCell<MyTrait>>不会遇到麻烦。)

\n\n

丢掉Box<>包装纸,你就可以自由轻松地施压Rc<RefCell<MyStruct>>了。Rc<RefCell<MyTrait>>回想一下,克隆 aRc<T>只是产生另一个Rc<T>,将引用计数增加一,您可以执行以下操作:

\n\n
use std::rc::Rc;\nuse std::cell::RefCell;\n\ntrait MyTrait {\n    fn trait_func(&self);\n}\n\n#[derive(Clone)]\nstruct MyStruct1;\nimpl MyStruct1 {\n    fn my_fn(&self) {\n        // do something\n    }\n}\n\nimpl MyTrait for MyStruct1 {\n    fn trait_func(&self) {\n        // do something\n    }\n}\n\nfn my_trait_fn(t: Rc<RefCell<MyTrait>>) {\n    t.borrow_mut().trait_func();\n}\n\nfn main() {\n    // (The type annotation is not necessary here, but helps explain it.\n    // If the `my_str.borrow().my_fn()` line was missing, it would actually\n    // be of type Rc<RefCell<MyTrait>> instead of Rc<RefCell<MyStruct1>>,\n    // essentially doing the coercion one step earlier.)\n    let my_str: Rc<RefCell<MyStruct1>> = Rc::new(RefCell::new(MyStruct1));\n    my_trait_fn(my_str.clone());\n    my_str.borrow().my_fn();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

作为一般规则,看看是否可以使事物通过引用获取包含的值,理想情况下甚至可以通用 \xe2\x80\x94fn my_trait_fn<T: MyTrait>(t: &T)和类似的,通常可以通过自动引用和取消引用来调用,my_str.borrow()以处理其余的 \xe2\x80 \x94而不是整个Rc<RefCell<MyTrait>>事情。

\n

  • 在夜间,可以将“T: Trait”的“Rc&lt;T&gt;”强制转换为“Rc&lt;Trait&gt;”...我不认为他想复制实际对象,否则没有理由使用“Rc”所有...您的最后一段是我的答案...不要传递“Rc&lt;RefCell&lt;Box&lt;X&gt;&gt;&gt;”疯狂,而只需调用“borrow”并传递引用 (4认同)
  • 不,正如我在对问题的评论中所说,`Rc&lt;RefCell&lt;T&gt;&gt;` -&gt; `Rc&lt;RefCell&lt;Trait&gt;&gt;` [每晚都很好](http://is.gd/zQUJqp) 和我真的不明白这怎么可能是一个问题,因为除非通过强制,否则你无法创建 `Rc&lt;RefCell&lt;Trait&gt;&gt;` 。 (2认同)