可变借用后的不可变引用

5

每次我使用Rust时,都会遇到与所有权/借用相关的类似问题,因此这里是最简单的代码片段,展示了我的常见问题:

use std::cell::RefCell;

struct Res {
    name: String,
}

impl Res {
    fn new(name: &str) -> Res {
        Res {
            name: name.to_string(),
        }
    }

    // I don't need all_res to be mutable
    fn normalize(&mut self, all_res: &Vec<Res>) {
        // [...] Iterate through all_res and update self.name
        self.name = "foo".to_string();
    }
}

fn main() {
    let res = RefCell::new(vec![Res::new("res1"), Res::new("res2")]);

    for r in res.borrow_mut().iter_mut() {
        // This panics at runtime saying it's
        // already borrowed (which makes sense, I guess).
        r.normalize(&*res.borrow());
    }
}

阅读了有关RefCell的内容后,我认为这会起作用。它可以编译,但在运行时会发生崩溃。

在迭代相同向量时如何引用向量?是否有更好的数据结构允许我这样做?

1个回答

6

您的程序出现了panic,因为您试图同时可变和不可变地借用Vec:这是不允许的。

相反,您需要仅在RefCell中包装String。这样可以在迭代Vec时修改字符串。

use std::cell::RefCell;

struct Res {
    name: RefCell<String>,
}

impl Res {
    fn new(name: &str) -> Res {
        Res {
            name: RefCell::new(name.to_string()),
        }
    }

    // I don't need all_res to be mutable
    fn normalize(&self, all_res: &Vec<Res>) {
        // [...] Iterate through all_res and update self.name
        *self.name.borrow_mut() = "foo".to_string();
    }
}

fn main() {
    let res = vec![Res::new("res1"), Res::new("res2")];

    for r in res.iter() {
        r.normalize(&res);
    }

    println!("{}", *res[0].name.borrow());
}

谢谢你的帮助 - 我在 Rust 的所有权规则方面仍然感到很迷茫。我想我会尝试开发一个简单的标记-清除垃圾收集器来练习这些规则。 - user3696012
1
@user3696012: 我想我会尝试开发一个简单的标记-清除垃圾收集器来练习这些规则。 => 尽量避免打开unsafe的舱门,当你理解所有权规则时已经很难了,但如果你还没有内化它们... - Matthieu M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接