我正试着通过阅读The Rust Programming Language Book来学习《 rust 》.我现在读的是第17章,在第Trade-offs of the State Pattern章的末尾,你们需要做以下事情:

  • 需要两次调用才能将状态更改为已发布.

你得到的代码是:

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
    }
}

所以我所理解的是,without breaking the trait signature,你必须实现某种逻辑到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,但这不起作用,因为我需要一个我没有的可变引用,如果不打破特征签名,我就不能拥有它.此外,这种方法可能还有更多我看不到的问题,实际上我对Rust还很陌生.

我真的不知道如何处理这个问题,所以任何帮助都是感激的.

推荐答案

然后在PendingReview状态的approve函数中调用ready_to_approve,但这不起作用,因为我需要一个我没有的可变引用,如果不打破特征签名,我就不能拥有它.

这是不准确的.State特征的approve函数拥有more,而不仅仅是一个可变的引用--它拥有整个self!你可以随心所欲地对它做任何事情,因为铁 rust 的所有权总是独一无二的.

要使approve内的self发生Mutations ,需要将其标记为mut.但请注意,与将&self更改为&mut selfthis does not affect the signature不同.这与拥有一个局部变量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分;
  2. 拨打add_review()是无效的,你必须说self.add_review().

您可以自己看到它编译并且不会 destruct 特征的签名(playground).

Rust相关问答推荐

为什么要在WASM库中查看Rust函数需要`#[no_mangle]`?

从Rust调用C++虚拟方法即使在成功执行之后也会引发Access违规错误

使用 struct 外部的属性来改变 struct 的原始方式

如何将像烫手山芋一样不透明的值从一个Enum构造函数移动到下一个构造函数?

如何用Axum/Tower压缩Html内容?

Tokio_Postgres行上未显示退回特性的生存期,且生命周期 不够长

在本例中,为什么我不能一次多次borrow 可变变量?

创建Rust中元对象协议的动态对象 Select /重新分配机制

循环访问枚举中的不同集合

如何迭代属性以判断相等性?

你能在Rust中弃用一个属性吗?

如何获取模块树?

在发布中包含 Rust DLL

如何为已实现其他相关 std trait 的每个类型实现一个 std Trait

将原始可变指针传递给 C FFI 后出现意外值

`use std::error::Error` 声明中断编译

当用作函数参数时,不强制执行与绑定的关联类型

为什么这个 Trait 无效?以及改用什么签名?

Rust:为什么在 struct 中borrow 引用会borrow 整个 struct?

这个 match 语句的默认值应该是什么,还有一种方法可以解开 Some case (chess in rust)