为什么除非我使用临时变量,否则我不能推入 dyn Trait 的 Vec?

Nic*_*ick 4 polymorphism traits rust parametric-polymorphism trait-objects

这是我的代码:

use std::rc::{Rc, Weak};
use std::cell::RefCell;

trait Trait {}

fn push<E: Trait>(e: E) {
    let mut v: Vec<Rc<RefCell<Box<dyn Trait>>>> = Vec::new();
    
    // let x = Rc::new(RefCell::new(Box::new(e)));
    // v.push(x); // error

    v.push(Rc::new(RefCell::new(Box::new(e)))); // works fine
}
Run Code Online (Sandbox Code Playgroud)

v.push(x)引发此错误:

error[E0308]: mismatched types
  --> src/main.rs:12:12
   |
7  | fn push<E: Trait>(e: E) {
   |         - this type parameter
...
12 |     v.push(x);
   |            ^ expected trait object `dyn Trait`, found type parameter `E`
   |
   = note: expected struct `std::rc::Rc<std::cell::RefCell<std::boxed::Box<dyn Trait>>>`
              found struct `std::rc::Rc<std::cell::RefCell<std::boxed::Box<E>>>`
Run Code Online (Sandbox Code Playgroud)

但是,如果我将值(使用完全相同的值和类型构造)直接推送到向量中,它会编译而不会出错。

那么为什么第一个版本不编译呢?x在将它推入向量之前,我应该更改什么以使其可以使用?

kfe*_*v91 7

这一切都在类型推断中。当你写:

v.push(Rc::new(RefCell::new(Box::new(e))));
Run Code Online (Sandbox Code Playgroud)

Rust 可以从该上下文中得知 to 的参数RefCell::new()必须是 a Box<dyn Trait>,因此尽管提供了 a Box<E>,它还是将其强制为前一种类型。另一方面,当你写这个时:

let x = Rc::new(RefCell::new(Box::new(e)));
v.push(x); // compile error
Run Code Online (Sandbox Code Playgroud)

Rust 首先推断x类型Rc<RefCell<Box<E>>>,您不能再将push其转换为vecof Rc<RefCell<Box<dyn Trait>>>。你可以通过在let绑定中放置一个显式类型注释来改变这一点,预先告诉 Rust 你确实想要一个Rc<RefCell<Box<dyn Trait>>>

use std::rc::{Rc, Weak};
use std::cell::RefCell;

trait Trait {}

fn push<E: Trait>(e: E) {
    let mut v: Vec<Rc<RefCell<Box<dyn Trait>>>> = Vec::new();

    let x: Rc<RefCell<Box<dyn Trait>>> = Rc::new(RefCell::new(Box::new(e)));
    v.push(x); // compiles
}
Run Code Online (Sandbox Code Playgroud)

操场

了解这里最重要的事情是E 不一样dyn TraitE是一些已知的Traitwhile 的具体实现,dyn Trait是一个 trait 对象,其底层具体实现已被删除。


归档时间:

查看次数:

656 次

最近记录:

4 年,7 月 前