首页 > 解决方案 > 是否可以在 rust 中编写动态的“抽象/共享”特征

问题描述

编辑:

原始问题

MyTrait我尝试分享复杂的功能doSth

MyTrait 是为 Foo 实现的。

Foo 有一个内部结构bar,其类型为T. 实现应防止为每个T.

#[derive(Debug)]
pub enum Status{
    Open,
    Closed,
}

#[derive(Debug)]
pub struct Foo<T>{
    name: String,
    status: Status,
    bar: T
    
}

#[derive(Debug)]
pub enum SomeError {
    Fails,
}

pub trait MyTrait<T> {
    type Output;
    
    fn setStatus(&self, status: Status) -> Status;
    fn getStatus(&self) -> Status;

    fn doSth(&self) -> Result<Self::Output, SomeError>
    {
        if super::variant_eq(&self.getStatus(), &Status::Closed) {
            self.setStatus(Status::Open);
            return Ok(T);
        };
        return Err(SomeError::Fails);
    }

}

impl<T> MyTrait<T> for Foo<T> {
    type Output = Foo<T>;

    fn setStatus(&self, status: Status) -> Status{
        self.status = status;
    }

    fn getStatus(&self) -> Status{
        self.status;
    }
    
}

doSth不编译(其他人可能也没有,它还没有走那么远)

我确实找到了泛型的示例,共享函数的示例,但没有找到该方法的示例,因此我不确定该方法是否合理。

如果朝着这个方向努力是合理的,那么前进的方向是什么?

标签: rust

解决方案


对于初学者,Status应该派生PartialEq以便您可以检查相等性。为 an实现自己的variant_eq函数enum几乎总是不正确的方法。

我还建议派生Copy以便于使用。

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Status {
    Open,
    Closed,
}

综上所述,这里有一些关于如何使您的代码正确运行的快速评论

pub trait MyTrait<T> {
    type Output;
    
    // This set should probably take a mutable reference
    fn set_status(&mut self, status: Status);
    fn get_status(&self) -> Status;

    // You need some way to get output
    fn get_output(&mut self) -> Self::Output;

    // Now it has everything it needs to work correctly.
    fn doSth(&mut self) -> Result<Self::Output, SomeError> {
        // Thanks to PartialEq we can use == as normal
        if self.getStatus() == Status::Closed {
            self.set_status(Status::Open);

            // Call function that will be implemented later to provide output
            return Ok(self.get_output())
        }

        // Return is assumed for last line in function
        Err(SomeError::Fails)
    }
}

即使你不能派生PartialEq,你至少可以使用一个匹配。

match self.getStatus() {
    Status::Closed => {
        self.set_status(Status::Open);
        Ok(self.get_output())
    }
    _ => Err(SomeError::Fails),
}

有了这一切,您就可以实现 foo 与您原来的类似。

impl<T> MyTrait<T> for Foo<T> {
    type Output = Foo<T>;

    // Required mutable reference to work
    fn set_status(&mut self, status: Status) {
        self.status = status;
    }

    fn get_status(&self) -> Status {
        // ; would have prevented value from being returned
        // Status also needs to implement Copy for this to work
        self.status
    }
    
    fn get_output(&mut self) -> Self::Output {
        // Since you have it return an owned value, you need to either clone
        // self, or make get_output consume self
        self.clone()
    }
}

推荐阅读