使用泛型实现特征时特征的不相容类型

时间:2015-04-19 13:12:12

标签: rust

编译以下代码:

use std::rc::Rc;
use std::cell::RefCell;

pub enum StorageType {
    // ...
}

pub trait Storable {
    fn get_nblocks(&self) -> usize;
    fn get_storage(&self) -> Rc<RefCell<Storage>>;
}

pub trait Storage {
    fn store(&mut self, data: &Storable);
    fn get_type(&self) -> &StorageType;
}

pub struct DataVolume<T: Storage> {
    nblocks: usize,
    storage: Rc<RefCell<T>>,
}
impl<T: Storage> DataVolume<T> {
    pub fn new(nblocks: usize, storage: Rc<RefCell<T>>) -> DataVolume<T> {
        let this = DataVolume { nblocks: nblocks, storage: storage.clone() };
        storage.borrow_mut().store(&this);
        this
    }
}
impl<T: Storage> Storable for DataVolume<T> {
    fn get_nblocks(&self) -> usize {
        self.nblocks
    }
    fn get_storage(&self) -> Rc<RefCell<T>> {
        self.storage.clone()
    }
}

给了我:

src/store.rs:37:5: 39:6 error: method `get_storage` has an incompatible type
 for trait: expected trait store::Storage, found type parameter [E0053]
src/store.rs:37     fn get_storage(&self) -> Rc<RefCell<T>> {
src/store.rs:38         self.storage.clone()
src/store.rs:39     }
error: aborting due to previous error

我尝试了很多东西,这就是我认为最终会正确的...... 我的数据结构设计本身在Rust世界中是错误的吗?

1 个答案:

答案 0 :(得分:2)

你的特质定义说:

fn get_storage(&self) -> Rc<RefCell<Storage>>

但您的实施是

fn get_storage(&self) -> Rc<RefCell<T>>

正如编译器告诉你的那样 - 这些不兼容。特征定义表示您将返回 unsized类型(可能或可能不可能,具体取决于)。该实现表示您将返回特定的类型,但将在编译时确定。

让我们选择通用解决方案,因为编译器将单态化(生成专用代码)您使用的每种类型。这可能会更快但涉及代码膨胀。将您的特质改为:

pub trait Storable<T>
    where T: Storage
{
    fn get_nblocks(&self) -> usize;
    fn get_storage(&self) -> Rc<RefCell<T>>;
}

然后整个程序看起来像(playpen):

use std::rc::Rc;
use std::cell::RefCell;

pub enum StorageType {
    // ...
}

pub trait Storable<T>
    where T: Storage
{
    fn get_nblocks(&self) -> usize;
    fn get_storage(&self) -> Rc<RefCell<T>>;
}

pub trait Storage {
    fn store(&mut self, data: &Storable<Self>);
    fn get_type(&self) -> &StorageType;
}

pub struct DataVolume<T>
    where T: Storage
{
    nblocks: usize,
    storage: Rc<RefCell<T>>,
}

impl<T> DataVolume<T>
    where T: Storage
{
    pub fn new(nblocks: usize, storage: Rc<RefCell<T>>) -> DataVolume<T> {
        let this = DataVolume { nblocks: nblocks, storage: storage.clone() };
        storage.borrow_mut().store(&this);
        this
    }
}

impl<T> Storable<T> for DataVolume<T>
    where T: Storage
{
    fn get_nblocks(&self) -> usize {
        self.nblocks
    }
    fn get_storage(&self) -> Rc<RefCell<T>> {
        self.storage.clone()
    }
}

fn main() {}