简体   繁体   English

如何将结构的 Vec 强制为特征对象的 Vec?

[英]How to coerce a Vec of structs to a Vec of trait objects?

Trying to create a DB struct that is a HashMap of vectors.尝试创建一个 DB 结构,它是向量的HashMap Each Vec contains Box<dyn Model> .每个Vec包含Box<dyn Model>

use std::collections::HashMap;

trait Model {
    fn id(&self) -> i32;
}

struct User;
struct Message;

impl Model for User {
    fn id(&self) -> i32 { 4 }
}

impl Model for Message {
    fn id(&self) -> i32 { 3 }
}

struct DB {
    users: Vec<Box<User>>,
    messages: Vec<Box<Message>>,
    tables: HashMap<String, Vec<Box<dyn Model>>>,
}

impl DB {
    fn new() -> Self {
        let users: Vec<Box<User>> = Vec::new();
        let messages: Vec<Box<Message>> = Vec::new();
        let mut tables: HashMap<String, Vec<Box<dyn Model>>> = HashMap::new();
        tables.insert("users".to_string(), users);
        tables.insert("messages".to_string(), messages);
        Self {
            users,
            messages,
            tables,
        }
    }
}

The compiler produces the following error:编译器产生以下错误:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:37:44
   |
37 |         tables.insert("users".to_string(), users);
   |                                            ^^^^^ expected trait Model, found struct `User`
   |
   = note: expected type `std::vec::Vec<std::boxed::Box<dyn Model>>`
              found type `std::vec::Vec<std::boxed::Box<User>>`

error[E0308]: mismatched types
  --> src/lib.rs:38:47
   |
38 |         tables.insert("messages".to_string(), messages);
   |                                               ^^^^^^^^ expected trait Model, found struct `Message`
   |
   = note: expected type `std::vec::Vec<std::boxed::Box<dyn Model>>`
              found type `std::vec::Vec<std::boxed::Box<Message>>`

Why can't the compiler infer that User and Message implement Model ?为什么编译器不能推断UserMessage实现Model

The types Box<dyn Model> and Box<User> are not interchangeable. Box<dyn Model>Box<User>类型不可互换。 Collections containing one cannot be directly transformed into the other, even with unsafe code. Collections 包含一个不能直接转换成另一个,即使是不安全的代码。 These types are different and have different representations in memory.这些类型不同,在 memory 中有不同的表示。 They even have different sizes:它们甚至有不同的尺寸:

println!("{}", std::mem::size_of::<Box<User>>());      // 8
println!("{}", std::mem::size_of::<Box<dyn Model>>()); // 16

The only way to convert from Vec<Box<User>> to Vec<Box<dyn Model>> is on an item-by-item basis.Vec<Box<User>>转换为Vec<Box<dyn Model>>的唯一方法是逐项进行。 Each item needs to be coerced like this:每个项目都需要像这样强制:

let model: Box<dyn Model> = user;

Or:或者:

let model = Box::<dyn Model>::from(user);

Resulting in this ugly thing:导致了这个丑陋的事情:

tables.insert(
    "users".to_string(),
    users
        .iter()
        .map(|user| Box::<dyn Model>::from(user))
        .collect()
);

If you don't need the original vector after this, you avoid cloning by making it mutable and draining instead:如果在此之后不需要原始向量,则可以通过使其可变和耗尽来避免克隆:

tables.insert(
    "users".to_string(),
    users
        .drain(..)
        .map(|user| Box::<dyn Model>::from(user))
        .collect(),
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM