我正在try 编写一个 struct ,它在一个Vec中拥有一些数据(或者可能包含一个可变引用的Vec——不太重要的是哪一个),它可以处理一个"操作"队列,其中每个操作都是某种计算,它会改变这个Vec的元素.以下是我迄今为止所写内容的一个小例子:
// some arbitrary data - may be large, so should not be cloned or copied
#[derive(PartialEq)]
struct T(i32, &'static str);
struct S(Vec<T>);
impl S {
fn get_mut(&mut self, t: &T) -> &mut T {
self.0.iter_mut().find(|a| *a == t).unwrap()
}
fn process_actions(&mut self, queue: ActionQueue) {
// some arbitrary calculation on the elements of self.0
for a in queue.actions {
let t1 = self.get_mut(a.t1);
t1.0 += a.t2.0;
}
}
}
#[derive(Debug)]
enum Error {
ActionError,
ActionQueueError,
}
struct Action<'a> {
s: &'a S,
t1: &'a T,
t2: &'a T,
}
impl<'a> Action<'a> {
pub fn new(s: &'a S, t1: &'a T, t2: &'a T) -> Result<Action<'a>, Error> {
if s.0.contains(&t1) && s.0.contains(&t2) {
Ok(Action { s, t1, t2 })
} else {
Err(Error::ActionError)
}
}
}
struct ActionQueue<'a> {
s: &'a S,
actions: Vec<Action<'a>>,
}
impl<'a> ActionQueue<'a> {
pub fn new(s: &'a S, actions: Vec<Action<'a>>) -> Result<ActionQueue<'a>, Error> {
if actions.iter().all(|a| std::ptr::eq(a.s, s)) {
Ok(ActionQueue { s, actions })
} else {
Err(Error::ActionQueueError)
}
}
}
fn main() -> Result<(), Error> {
let t1 = T(1, "a");
let t2 = T(2, "b");
let mut s = S(vec![t1, t2]);
let a = Action::new(&s, &t1, &t2)?; // error: borrow of moved value: `t1`
let q = ActionQueue::new(&s, vec![a])?;
s.process_actions(q); // cannot borrow `s` as mutable because it is also borrowed as immutable
Ok(())
}
这有几个问题:
- 我无法创建动作,因为t1和t2已被移动.
- 即使可以,我也无法处理操作队列,因为s已经在操作中被永久borrow .我希望Action(和ActionQueue)包含对s的引用的原因是,据我所知,最好使用类型来防止创建无效数据,例如引用s中未包含的数据的Action(由s处理).
- S的
get_mut
个函数似乎有点奇怪,有点粗糙,好像我不需要这样的函数.
我理解错误发生的原因以及它们的含义,但我不认为有任何方法可以绕过这个问题,因为为了定义任何操作,我需要参考s.0
的元素,而我不允许这样做.所以我的问题是,这段代码应该如何重写,以便它能够真正编译?设计是否完全不同并不重要,只要它实现了相同的目标(即允许将稍后处理的操作排队).