Rust面向对象设计模式

egdjgwm8  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(135)

我正在尝试通过阅读The Rust Programming Language Book来学习Rust。我现在读到第17章,在状态模式的权衡结束时,你被要求做以下事情:

  • 在将状态更改为Published之前,需要两次调用以进行批准。

你得到的代码是:

pub struct Post {
    state: Option<Box<dyn State>>,
    content: String
}

impl Post {
    pub fn new() -> Post {
        Post {
            state: Some(Box::new(Draft {})),
            content: String::new(),
        }
    }

    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }

    pub fn content(&self) -> &str {
        self.state.as_ref().unwrap().content(self)
    }

    pub fn request_review(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.request_review())
        }
    }

    pub fn approve(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.approve())
        }
    }
}

trait State {
    fn request_review(self: Box<Self>) -> Box<dyn State>;
    fn approve(self: Box<Self>) -> Box<dyn State>;
    fn content<'a>(&self, post: &'a Post) -> &'a str {
        ""
    }
}

struct Draft {}

impl State for Draft {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        Box::new(PendingReview {})
    }

    fn approve(self: Box<Self>) -> Box<dyn State> {
        self
    }
}

struct PendingReview {}

impl State for PendingReview {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        self
    }

    fn approve(self: Box<Self>) -> Box<dyn State> {
        Box::new(Published {})
    }
}

struct Published {}

impl State for Published {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        self
    }

    fn approve(self: Box<Self>) -> Box<dyn State> {
        self
    }

    fn content<'a>(&self, post: &'a Post) -> &'a str {
        &post.content
    }
}

所以我的理解是,在不破坏trait签名的情况下,你必须对PendingReview实现某种逻辑,以便需要两次批准才能更改为Published状态。
我想做点什么

struct PendingReview {
    reviews: i32,
}

impl PendingReview {
    fn add_review(&mut self) {
        self.reviews += 1;
    }

    pub fn ready_to_approve(&self) -> bool {
        if self.reviews == 2 {
            return true;
        }
        add_review();
        return false;
    }
}

然后在PendingReview状态的approve函数中调用ready_to_approve,但这不起作用,因为我需要一个可变引用,而我没有,而且我不能在不破坏trait签名的情况下拥有它。这种方法可能还有更多我看不到的问题,实际上我对Rust很陌生。
我真的不知道如何处理这个问题,所以任何帮助都很感激。

xnifntxz

xnifntxz1#

然后在PendingReview状态的approve函数中调用ready_to_approve,但这不起作用,因为我需要一个可变引用,而我没有,而且我不能在不破坏trait签名的情况下拥有它。
这是不准确的。State trait的approve函数不仅仅有一个可变引用-它拥有整个self!你可以做任何你想做的事情,因为Rust的所有权总是排他性的。
要在approve内部改变self,您需要将其标记为mut。但请注意,与将&self更改为&mut self不同,这不会影响签名。这就像有一个局部变量let x,然后决定需要对其进行变异,并将其更改为let mut x;它只是告诉编译器你希望发生变化,但它仍然是同一个变量,具有相同的类型-函数参数也是如此。
考虑到这一点,PendingReviewapprove可以是:

fn approve(mut self: Box<Self>) -> Box<dyn State> {
    if self.ready_to_approve() {
        Box::new(Published {})
    }
    else {
        self
    }
}

你的代码中还有一些其他问题需要修复:

  1. ready_to_approve需要&mut self;
    1.调用add_review()是无效的,你必须说self.add_review().
    你可以自己看到它编译并且没有破坏trait的签名(playground)。

相关问题