从Rust中的可变函数调用不可变函数

时间:2019-06-25 21:38:26

标签: rust

我有一些结构:

struct data {
    payload: i32,
}

struct bar {
    datas: Vec<data>,
}

impl bar {
    pub fn f2(&self, dta: &mut data) {
        dta.payload = 1;
    }

    pub fn f1(&mut self) {
        let zeroes = self.datas.iter_mut().filter(|b| b.payload == 0);
        for zero in zeroes {
            self.f2(zero);
        }
    }
}

当我尝试编译它时,编译器会抱怨:

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/lib.rs:17:13
   |
15 |         let zeroes = self.datas.iter_mut().filter(|b| b.payload == 0);
   |                      ---------- mutable borrow occurs here
16 |         for zero in zeroes {
   |                     ------ mutable borrow later used here
17 |             self.f2(zero);
   |             ^^^^ immutable borrow occurs here

我明白了为什么编译器不允许我这样做;错误消息是非常好的。有没有做这种事情的好方法而编译器不会抱怨呢?这种行为会阻止某些我认为会有所帮助的代码结构形式,例如将给定成员struct实例的处理传递给另一个函数-上面的例子很简单,我们可以轻松地就地修改每个给定的“零”实例,但是,如果f2包含复杂的逻辑,则可能会使f1中的代码。我知道,在这种情况下,也可以使用关联的函数,但是再说一次:此示例已简化,如果f2需要对该结构的其他字段进行读取访问,则关联的函数将不起作用。

到目前为止,我提出的一种解决方案是不使用迭代器,而是使用带数据结构副本的for循环:

pub fn f1(&mut self) {
    for i in 0..self.datas.len() {
        if self.datas[i].payload == 0 {
            let mut d0 = *self.datas.get_mut(i).unwrap();
            self.f2(&mut d0);
        }
    }
}

虽然这可以在某些地方使用(甚至可能实际上与迭代器一起使用),但还是有点失误了,因为d0现在是一个副本,这意味着必须将d0复制回来进入self.datas。同样,这个“解决方案”要求我们实现Copy特性,这对于复杂的结构可能是乏味的(..并且在运行时很昂贵)。

正确的方法是什么?

0 个答案:

没有答案