首页 > 解决方案 > 如何处理 trait 对象中的 Sized 要求?

问题描述

我无法理解 Rust 中的特征和对象安全性。

我有一个StoreTrait用于存储一些数据的Resource结构和一个包含对 a 的引用的结构StoreTrait

我希望Resource有对实例的引用store,因为Resource将使用的许多方法store,并且我不想显式传递store给 上的每个方法Resource

我还需要将逻辑驻留在特征中,因为我有各种需要共享它的实现(内存中和磁盘存储)。所以把它移到 impl 中并不是我想要的。

Storetrait 中,我尝试传递&Self给一个函数,但它失败了,因为&Selfis not Sized

pub trait StoreTrait {
    fn create_resource(&self) {
        let agent = Resource::new(self);
    }
}

struct Resource<'a> {
    store: &'a dyn StoreTrait,
}

impl<'a> Resource<'a> {
    pub fn new(store: &dyn StoreTrait) -> Resource {
        Resource { store }
    }
}
error[E0277]: the size for values of type `Self` cannot be known at compilation time
 --> src/lib.rs:3:35
  |
3 |         let agent = Resource::new(self);
  |                                   ^^^^ doesn't have a size known at compile-time
  |
  = note: required for the cast to the object type `dyn StoreTrait`
help: consider further restricting `Self`
  |
2 |     fn create_resource(&self) where Self: Sized {
  |                               ^^^^^^^^^^^^^^^^^

这可能会成为 XY 问题

编译器建议where Self: Sized在这些方法中使用边界。但是,这在稍后save_resource()从 a调用时会导致另一个问题Resource,因为这意味着我正在调用带有Sized边界的 trait 对象上的方法。

pub trait StoreTrait {
    // So after adding the trait bounds here...
    fn create_resource(&self)
    where
        Self: Sized,
    {
        let agent = Resource::new(self);
    }

    // And here (internal logic requires that)...
    fn save_resource(&self, resource: Resource)
    where
        Self: Sized,
    {
        // This now requires `Self: Sized`, too!
        self.create_resource()
    }
}

pub struct Resource<'a> {
    pub store: &'a dyn StoreTrait,
}

impl<'a> Resource<'a> {
    pub fn new(store: &dyn StoreTrait) -> Resource {
        Resource { store }
    }

    pub fn save(&self) {
        self.store.save_resource(self)
    }
}

操场

error: the `save_resource` method cannot be invoked on a trait object
  --> src/lib.rs:26:20
   |
13 |         Self: Sized;
   |               ----- this has a `Sized` requirement
...
26 |         self.store.save_resource(self)
   |                    ^^^^^^^^^^^^^

如何规避设置特征界限?或者如何防止在 trait 对象上调用方法?也许我正在做其他没有意义的事情?

编辑:我最终改变了函数的参数。每当我使用&dyn StoreTrait时,我都会切换到&impl StoreTrait. 这意味着每个实现都会编译具有该签名的函数,这使得二进制文件更大一些,但它现在sized可以满足要求。耶!

标签: rusttrait-objects

解决方案


也许如果你只是将函数从特征移动到每个实现它会做你想要的?

fn main() {}

pub trait StoreTrait {
    fn create_resource(&self);

    fn save_resource(&self, resource: &Resource);
}

struct Resource<'a> {
    store: &'a dyn StoreTrait,
}

impl<'a> Resource<'a> {
    pub fn new(store: &dyn StoreTrait) -> Resource {
        Resource { store }
    }

    pub fn edit(&self) {
        self.store.save_resource(self)
    }
}

struct StoreMem {
    resources: Vec<String>,
}

impl StoreTrait for StoreMem {
    fn create_resource(&self) {
        let agent = Resource::new(self);
    }
    
    fn save_resource(&self, resource: &Resource) {
        //
    }
}

struct StoreDisk {
    resources: Vec<String>,
}

impl StoreTrait for StoreDisk {
    fn create_resource(&self) {
        let agent = Resource::new(self);
    }
    
    fn save_resource(&self, resource: &Resource) {
        //
    }
}

推荐阅读