Код работает без заимствований, но я не могу заставить его работать с заимствованиями - PullRequest
1 голос
/ 10 апреля 2019

У меня есть некоторый код, и он работает, но заимствование AFAIK сделано специально, чтобы избежать передачи одного и того же объекта в метод вручную, как я делал в методе split_text.

fn main() {
    println!("Hello, world!");
    let mut test = String::from("12345");
    let mut obj1 = Object {
        text: test.as_mut_str(),
        next: None,
    };
    for i in 0..5 {
        obj1 = obj1.split_text(4 - i);
        if let Some(obj) = obj1.next.as_ref() {
            println!("{}", obj.text);
        }
    }
}

struct Object<'a> {
    text: &'a mut str,
    next: Option<Box<Object<'a>>>,
}

impl<'a> Object<'a> {
    fn split_text(mut self, count: usize) -> Self {
        let tmp = self.text;
        let (part1, part2) = tmp.split_at_mut(count);
        self.text = part1;
        let obj2 = Object {
            text: part2,
            next: None,
        };
        self.next = Some(Box::new(obj2));
        self
    }
}

( Playground)

Но я не могу понять, как пройти проверку заимствования

impl<'a> Object<'a> {
    fn split_text(&'a mut self, count: usize) {
        let tmp = &mut self.text;
        let (part1, part2) = tmp.split_at_mut(count);
        self.text = part1;
        let obj2 = Object {
            text: part2,
            next: None,
        };
        self.next = Some(Box::new(obj2));
    }
}

приводит к ошибке

error[E0499]: cannot borrow `obj1` as mutable more than once at a time
  --> src/main.rs:11:9
   |
11 |         obj1.split_text(4 - i);
   |         ^^^^ mutable borrow starts here in previous iteration of loop

error[E0502]: cannot borrow `obj1.next` as immutable because it is also borrowed as mutable
  --> src/main.rs:12:28
   |
11 |         obj1.split_text(4 - i);
   |         ---- mutable borrow occurs here
12 |         if let Some(obj) = obj1.next.as_ref() {
   |                            ^^^^^^^^^
   |                            |
   |                            immutable borrow occurs here
   |                            mutable borrow later used here

error[E0506]: cannot assign to `self.text` because it is borrowed
  --> src/main.rs:27:9
   |
23 | impl <'a> Object<'a> {
   |       -- lifetime `'a` defined here
24 |     fn split_text(&'a mut self, count:usize) {
25 |         let tmp = &mut self.text;
   |                   -------------- borrow of `self.text` occurs here
26 |         let (part1, part2) = tmp.split_at_mut(count);
   |                              ----------------------- argument requires that `self.text` is borrowed for `'a`
27 |         self.text = part1;
   |         ^^^^^^^^^^^^^^^^^ assignment to borrowed `self.text` occurs here

( Детская площадка )

Есть ли способ заставить этот код работать?

1 Ответ

1 голос
/ 10 апреля 2019

Проблема заключается в том, что вы заимствуете объект obj1 изменяемый в функции split_text на 'a время жизни до конца функции main.

fn main() {
    println!("Hello, world!");
    let mut test = String::from("12345");
    let mut obj1 = Object {                             // 'a start
        text: test.as_mut_str(),
        next: None,
    };
    for i in 0..5 {
        obj1 = obj1.split_text(4 - i);                  // borrow for 'a lifetime,
                                                        // Won't work in next iteration
        if let Some(obj) = obj1.next.as_ref() {         // Won't work
            println!("{}", obj.text);
        }
    }
}                                                       // 'a end

Вы хотитезаимствовать его только для функции split_text, то есть для другого (меньшего) времени жизни - которое вы можете либо исключить, либо указать другое - скажем, 'b.

struct Object<'a> {
    text: &'a str, // no need of mutable slice here
    next: Option<Box<Object<'a>>>,
}

impl<'a> Object<'a> {
    fn split_text(&mut self, count: usize) { // No lifetime required here
        let (part1, part2) = self.text.split_at(count); // no need of temp var and mutable split here
        self.text = part1;
        let obj2 = Object {
            text: part2,
            next: None,
        };
        self.next = Some(Box::new(obj2));
    }
}

Явная другая версия времени жизни (простодля полноты):

impl<'a> Object<'a> {
    fn split_text<'b>(&'b mut self, count: usize) {
        let tmp = &mut self.text;
        let (part1, part2) = tmp.split_at(count);
        self.text = part1;
        let obj2 = Object {
            text: part2,
            next: None,
        };
        self.next = Some(Box::new(obj2));
    }
}

Также сделайте что-нибудь изменяемое только при необходимости.Я изменил изменяемый фрагмент и разделился на обычный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...