rust - 如何将结构的 Vec 强制转换为特征对象的 Vec?

标签 rust traits trait-objects

试图创建一个 HashMap 的数据库结构向量。每个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,
        }
    }
}

编译器产生以下错误:

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

为什么编译器不能推断出 UserMessage实现 Model

最佳答案

类型 Box<dyn Model>Box<User>不可互换。包含一个的集合不能直接转换为另一个,即使使用不安全的代码也是如此。这些类型不同,在内存中有不同的表示。它们甚至有不同的尺寸:

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

Vec<Box<User>> 转换的唯一方法至 Vec<Box<dyn Model>>是逐项计算的。每个项目都需要这样强制转换:

let model: Box<dyn Model> = user;

或者:

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

导致这丑陋的事情:

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

如果在此之后您不需要原始向量,则可以通过使其可变和耗尽来避免克隆:

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

关于rust - 如何将结构的 Vec 强制转换为特征对象的 Vec?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58683548/

相关文章:

rust - Rust 中的可变Arc

c++模板特征——编译时不包含头文件

generics - 为什么 `&(?Sized + Trait)`无法转换为 `&dyn Trait`?

Rust String 与 &str 迭代器

oop - 是否可以从特征中访问结构字段?

generics - 如何在Rust中创建对通用特征对象的引用的Vec? [复制]

rust - 如何将特征转换为具体类型?

rust - 如何在 WebAssembly 中从 Rust 返回一个字符串(或类似字符串)?

rust - 将属性应用于宏扩展

multithreading - 为什么 Rust playground 不会为线程产生不同的结果?