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

问题描述 投票:1回答:1

这是我的代码。

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
}

这是我的代码: 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>>>`
   = help: type parameters must be constrained to match other types
   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

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

那么为什么第一个版本不能编译呢?我应该怎么做才能使我能够使用 x 在把它推送到向量之前?

rust traits
1个回答
6
投票

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

v.push(Rc::new(RefCell::new(Box::new(e))));

Rust可以从这个上下文中判断出参数到 RefCell::new() 必须是 Box<dyn Trait>因此,尽管提供了一个 Box<E>,它胁迫它到前一种类型。另一方面,当你这样写时。

let x = Rc::new(RefCell::new(Box::new(e)));
v.push(x); // compile error

Rust首先推断出 x 类型 Rc<RefCell<Box<E>>> 而你不能再 push 化为 vecRc<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
}

游乐场

这里要明白的是 E 不一样 作为 dyn Trait. E 是一些已知的具体实施 Traitdyn Trait 是一个特质对象,其底层的具体实现被抹去。

© www.soinside.com 2019 - 2024. All rights reserved.