来自权威指南的小练习,关于面向对象中的状态模式。
pub struct Post {
state: Option<Box<dyn State>>,
content:String,
}
post实例有多个状态,为了限制每个状态下的行为,方法都写在trait State里。比如
impl Post {
// skip
pub fn content(&self) -> &str {
if let Some(s) = &self.state {
return s.content(self);
} else {
return "";
}
}
}
trait State {
// skip
fn content<'a>(&self, post: &'a Post) -> &'a str {
""
}
}
struct Published {}
impl State for Published {
// skip
fn content<'a>(&self, post: &'a Post) -> &'a str {
&post.content
}
}
这样调用post.content()的时候,只有state为Published的时候才会去访问content。 现在有个写入content的需求,辣我就写:
impl Post {
// skip
pub fn add_text(&mut self,text: &str) {
self.state.as_mut().unwrap().add_text(self,text);
}
}
impl State for Draft {
// skip
fn add_text(&self, post: &mut Post, text:&str) {
post.content.push_str(text);
}
}
然后就报错了
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src\lib.rs:15:47
|
15 | self.state.as_mut().unwrap().add_text(self,text);
| ---------- -------- ^^^^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
error: aborting due to previous error
说是引用规则的问题,用state的时候引用了self,然后给add_text传参的self又是一次mut 引用,违反了规则。add_text要通过引用self来获得,而add_text又需要传入self的mut引用,两个引用的scope隔离不开来。 小弟走投无路只想到用RefCell,感觉像耍赖。 小弟在此请教,请问该怎么解决这个问题呢?
1
共 9 条评论, 1 页
评论区
写评论get到了!这种取值出来就不会保留引用,我原本那种链式会一直保留引用。
--
👇
eweca: 我也觉得这个写法有点奇怪,不过官方书TRPL第17.3章节有几乎一模一样的例子。 官网书的写法是直接在impl Post里面写而不是把它写进trait,当然,这会导致所有状态下都可以修改文档:
TRPL里的代码如下:
如果你想只能在Draft或某几种状态下写入,才需要按照你这个写法吧?你这个写法的问题是你在不可变借用self.state的情况下还想拿到self的可变借用,解法可以借鉴官方书里函数request_review。 上面已给出这个函数作为模板:
一个小修改,add_text只需要获得不可变借用即可。
我也觉得这个写法有点奇怪,不过官方书TRPL第17.3章节有几乎一模一样的例子。 官网书的写法是直接在impl Post里面写而不是把它写进trait,当然,这会导致所有状态下都可以修改文档:
TRPL里的代码如下:
如果你想只能在Draft或某几种状态下写入,才需要按照你这个写法吧?你这个写法的问题是你在不可变借用self.state的情况下还想拿到self的可变借用,解法可以借鉴官方书里函数request_review。 上面已给出这个函数作为模板:
确实有一种递归改动的赶脚,不太科学
--
👇
Mike Tang: rust 中一般不会/不应出现
self.foo(self, bar);
这样的代码。 搞复杂了吧。
是书上的教例,在讲面向对象的状态模式,所以有丶像java吧可能
--
👇
shaitao: 不需要像java那么蹩脚的
有一说一,确实
--
👇
Ryan-Git: 这代码写出来保管一个礼拜后就看不懂了,太绕了
这代码写出来保管一个礼拜后就看不懂了,太绕了
rust 中一般不会/不应出现
self.foo(self, bar);
这样的代码。 搞复杂了吧。
不需要像java那么蹩脚的