为什么除非我使用临时变量,否则我不能推入 dyn Trait 的 Vec? [英] Why can't I push into a Vec of dyn Trait unless I use a temporary variable?

查看:81
本文介绍了为什么除非我使用临时变量,否则我不能推入 dyn Trait 的 Vec?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码:

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>>>`

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

But if I push the value (constructed with the exact same value and types) directly into the vector it compiles without error.

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

So why doesn't the first version compile? And what should I change to make it so that I can use x before pushing it into the vector?

推荐答案

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

It's all in the type inference. When you write:

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

Rust 可以从上下文中判断 RefCell::new() 的参数必须是 Box,所以尽管提供了 Box<;E>,它将其强制为前一种类型.另一方面,当你写这个时:

Rust can tell from that context that the argument to RefCell::new() must be a Box<dyn Trait>, so despite supplying a Box<E>, it coerces it to the former type. When you write this on the other hand:

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

Rust 首先推断 Rc<RefCell<Box<E>>> 类型的 x 并且你不能再push它转化为 Rc>>vec.你可以通过在你的 let 绑定中放置一个显式类型注释来改变这一点,提前告诉 Rust 你真的想要一个 Rc>>:

Rust first infers that x of type Rc<RefCell<Box<E>>> and you can no longer push it into a vec of Rc<RefCell<Box<dyn Trait>>>. You can change this by putting an explicit type annotation in your let binding to tell Rust upfront that you really do want a 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 是一些已知的 Trait 的具体实现,而 dyn Trait 是一个 trait 对象,其底层具体实现已被删除.

The important thing to understand here is that E is not the same as dyn Trait. E is some known concrete implementation of Trait while dyn Trait is a trait object with its underlying concrete implementation erased.

这篇关于为什么除非我使用临时变量,否则我不能推入 dyn Trait 的 Vec?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆