Есть ли способ заимствовать RefCell неизменным и изменчивым одновременно? - PullRequest
0 голосов
/ 07 июня 2019

У меня есть кусок кода, который должен работать со списком.Этот список содержит элементы из другого источника, которые необходимо обработать и в конечном итоге удалить.Список также передается нескольким функциям, которые решают, добавлять или удалять элемент.Я создал пример кода, который отражает мою проблему:

use std::{cell::RefCell, rc::Rc};

pub fn foo() {
    let list: Rc<RefCell<Vec<Rc<RefCell<String>>>>> = Rc::new(RefCell::new(Vec::new()));

    list.borrow_mut()
        .push(Rc::new(RefCell::new(String::from("ABC"))));

    while list.borrow().len() > 0 {
        let list_ref = list.borrow();

        let first_item = list_ref[0].borrow_mut();
        //item processing, needed as mutable

        list.borrow_mut().remove(0);
    }
}

Эта паника во время выполнения:

thread 'main' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:997:5

Мне кажется, я понимаю проблему: у меня есть два неизменных заимствования, а затем третье, котороеизменчивоСогласно документам Rust, это недопустимо: либо много неизменных заимствований, либо одно изменяемое.Есть ли способ обойти эту проблему?

1 Ответ

1 голос
/ 08 июня 2019

Я понятия не имею, чего вы на самом деле пытаетесь достичь, поскольку вы не смогли предоставить минимальный воспроизводимый пример , но я думаю, что вы просто перепутали заимствования list и item в вашей структуре данных, и это смутило вас в первую очередь.

Тем не менее следующий код (который вы можете запустить на детской площадке ) делает то, что вы описали выше.

use std::{cell::RefCell, rc::Rc};

pub fn foo() {
    let list = Rc::new(RefCell::new(Vec::new()));
    let mut list = list.borrow_mut();

    let item = Rc::new(RefCell::new(String::from("ABC")));

    list.push(item);
    println!("list: {:?}", list);

    while let Some(item) = list.pop() {
        println!("item: {:?}", item);
        item.borrow_mut().push_str("DEF");
        println!("item: {:?}", item);
    }

    println!("list: {:?}", list);
}

fn main() {
    foo();
}

Здесь я использовал два трюка.

  1. Я одолжил list только один раз, и этот заем был изменчивым, что позволило мне добавлять и удалять предметы из него.

  2. Поскольку в вашем описании говорилось, что вы все равно хотите удалить элементы из list, я смог перебрать Vec с помощью методов pop или remove (в зависимости от порядка хотите получить предметы из list). Это означает, что мне не нужно было заимствовать Vec для области видимости цикла (что в противном случае вы бы сделали, если бы перебрали его).

Существуют и другие способы удаления элемента на основе некоторого предиката. Например: Удаление элементов из Vec на основе некоторого условия .

На самом деле, чтобы ответить на ваш первоначальный вопрос: нет никакого способа получить неизменный и изменяемый заем одновременно. Это один из основных принципов Rust, который делает его безопасным для памяти. Подумайте об этом, какой гарантией будет неизменность, если в то же время под капотом данные действительно могут измениться?

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