在 Rust 中克隆一个 Rc 指针到一个特征对象上?

Mar*_*ark 5 smart-pointers traits rust trait-objects

我正在学习 Rust,不明白为什么以下内容不起作用。我想我们无法在特征对象上克隆 Rc 指针?我如何将这样的引用传递给仅由特征定义的函数,如尝试的那样some_function

use std::rc::Rc;

trait SomeTrait {}
struct SomeThing {}
impl SomeTrait for SomeThing {}

fn some_function(s: Rc<dyn SomeTrait>) {}
fn another_function(s: &Rc<dyn SomeTrait>) {}

fn main() {
    let s = Rc::new(SomeThing{});

    // This doesnt work
    some_function(Rc::clone(&s));

    // I could do this
    some_function(s);

    // But then I could not do this
    some_function(s);
    
    // For that matter, neither can I do this
    another_function(&s);
}
Run Code Online (Sandbox Code Playgroud)

Mas*_*inn 6

如果您查看编译器的错误消息,您将看到以下内容:

error[E0308]: mismatched types
   |
14 |     some_function(Rc::clone(&s));
   |                             ^^ expected trait object `dyn SomeTrait`, found struct `SomeThing`
   |
   = note: expected reference `&Rc<dyn SomeTrait>`
              found reference `&Rc<SomeThing>`
Run Code Online (Sandbox Code Playgroud)

s这意味着编译器错误地推断了to的类型,Rc<SomeThing>而不是Rc<dyn SomeTrait>您正在寻找的类型,这可以通过提供明显错误的类型 to 的常见技巧来确认let s

error[E0308]: mismatched types
  --> src/main.rs:11:17
   |
11 |     let s: () = Rc::new(SomeThing{});
   |            --   ^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Rc`
   |            |
   |            expected due to this
   |
   = note: expected unit type `()`
                 found struct `Rc<SomeThing>`
Run Code Online (Sandbox Code Playgroud)

由于 Rust 包装器是不变的,anRc<SomeThing>和 anRc<dyn SomeTrait>完全不兼容的值,因此无法仅将一个值用于另一个值。

解决方案是简单地正确明确s地键入:

use std::rc::Rc;

trait SomeTrait {}
struct SomeThing {}
impl SomeTrait for SomeThing {}

fn some_function(s: Rc<dyn SomeTrait>) {}
fn another_function(s: &Rc<dyn SomeTrait>) {}

fn main() {
    let s: Rc<dyn SomeTrait> = Rc::new(SomeThing{});

    // This doesnt work
    some_function(Rc::clone(&s));
    
    // For that matter, neither can I do this
    another_function(&s);
}
Run Code Online (Sandbox Code Playgroud)

显然,中间的两个调用无法工作,因为第一个调用将移动local Rc,而第二个调用(和最后一个调用)仍然想要移动 local 。

  • 值得注意的是:您_可以_将 `Rc&lt;SomeThing&gt;` 转换为 `Rc&lt;dyn SomeTrait&gt;`,但它需要显式转换。`some_function(Rc::clone(&amp;s) as Rc&lt;dyn SomeTrait&gt;);` 将编译并工作。这是由于当前不稳定的“CoerceUnsized”特征造成的。 (5认同)