Как решить основные проблемы заимствования?

#rust

Вопрос:

Я довольно новичок в rust, и я застрял на том, что, вероятно, очень простой вопрос о заимствовании. Я упростил свой код, как показано ниже:

 pub struct MyStruct {
    pub val: i32
}

impl MyStruct {
    pub fn new(val: i32) -> Self {
        MyStruct {
            val
        }
    }
}

pub struct MyStructVec {
    pub vec: Vec::<MyStruct>
}

impl MyStructVec {
    pub fn new() -> Self {
    MyStructVec {
           vec: Vec::new()
        }
    }

    pub fn insert(amp;mut self, mut my_struct: MyStruct) {
        self.vec.push(my_struct);
    }

    fn run(amp;mut self) {
        for s in self.vec.iter_mut() {
            s.val = s.val   1;
            self.edit(s);
        }
    }

    fn edit(amp;self, my_struct: amp;mut MyStruct) {
        my_struct.val = my_struct.val * 2;
    }
}

fn main() {

    let mut my_struct1 = MyStruct::new(69);
    let mut my_struct2 = MyStruct::new(420);
    let mut my_struct_vec = MyStructVec::new();
    my_struct_vec.insert(my_struct1);
    my_struct_vec.insert(my_struct2);

    my_struct_vec.run();
}
 

Когда я запускаю это, я получаю следующую ошибку:

 error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/main.rs:33:13
   |
31 |         for s in self.vec.iter_mut() {
   |                  -------------------
   |                  |
   |                  mutable borrow occurs here
   |                  mutable borrow later used here
32 |             s.val = s.val   1;
33 |             self.edit(s);
   |             ^^^^ immutable borrow occurs here
 

Но если я отредактирую свой код следующим образом:

     fn run(amp;mut self) {
        for s in self.vec.iter_mut() {
            s.val = s.val   1;
            //self.edit(s);
            s.val = s.val * 2;
        }
    }
 

Тогда он работает отлично. Это пример упрощенного случая, но в моем реальном коде я мог бы просто выделить свой код в отдельную функцию для удобства чтения, например, с помощью функции редактирования. Итак, каков правильный способ сделать это в Rust? Большое спасибо!

Комментарии:

1. Зачем MyStructVec::edit получать неизменяемую ссылку на self , когда он ее не использует?

2. «Возможно, я просто захочу выделить свой код в отдельную функцию для удобства чтения» — подпись функции — это ваш контракт с компилятором. edit() Функция говорит, что ей нужна ссылка на self , но вам также нужно self одновременно изменять часть, что недопустимо. Если вам нужно что-то из self при редактировании a MyStruct , то у вас должна быть функция только с этими частями, чтобы они не могли конфликтовать. Разделение кода должно следовать за разделением контракта.

Ответ №1:

Я думаю, ошибка заключается в том, что по какой-то причине вы вносите MyStructVec изменения MyStruct , когда это может быть простой метод MyStruct . Вы возитесь с большим количеством ссылок, которые вам нужны, и на самом деле вы не берете те, которые вам нужны. Кажется справедливым, что edit это должно быть инкапсулировано в объект, который будет изменен:

 
impl MyStruct {
...
    
    fn edit(amp;mut self) {
        self.val = self.val * 2;
    }
}
...

impl MyStructVec {
...
    fn run(amp;mut self) {
        for s in self.vec.iter_mut() {
            s.val = s.val   1;
            s.edit();
        }
    }
}

 

Игровая площадка