如何将结构的 Vec 强制转换为特征对象的 Vec? [英] How to coerce a Vec of structs to a Vec of trait objects?

查看:42
本文介绍了如何将结构的 Vec 强制转换为特征对象的 Vec?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

试图创建一个数据库结构,它是向量的 HashMap.每个Vec包含Box.

Trying to create a DB struct that is a HashMap of vectors. Each Vec contains 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?

Why can't the compiler infer that User and Message implement Model?

推荐答案

BoxBox 类型不可互换.即使使用不安全的代码,包含一个的集合也不能直接转换为另一个.这些类型是不同的,并且在内存中有不同的表示.它们甚至有不同的尺寸:

The types Box<dyn Model> and Box<User> are not interchangeable. Collections containing one cannot be directly transformed into the other, even with unsafe code. These types are different and have different representations in memory. They even have different sizes:

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

Vec> 转换为 Vec> 的唯一方法是逐项转换.每个项目都需要像这样被强制:

The only way to convert from Vec<Box<User>> to Vec<Box<dyn Model>> is on an item-by-item basis. Each item needs to be coerced like this:

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()
);

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

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(),
);

这篇关于如何将结构的 Vec 强制转换为特征对象的 Vec?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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