我希望能够构造包含对可变缓冲区对象的不可变引用的对象。以下代码不起作用,但说明了我的用例,是否有惯用的 Rust 方法来处理这个问题?
#[derive(Debug)]
struct Parser<'a> {
buffer: &'a String
}
fn main() {
let mut source = String::from("Peter");
let buffer = &source;
let parser = Parser { buffer };
// How can I legally change source?
source.push_str(" Pan");
println!("{:?}", parser);
}
最佳答案
rust borrow checker 的黄金法则是:一次只有一个写入者或多个读取者可以访问一个资源。这确保了算法可以安全地在多线程中运行。
你在这里违反了这条规则:
#[derive(Debug)]
struct Parser<'a> {
buffer: &'a String
}
fn main() {
// mutable access begins here
let mut source = String::from("Peter");
// immutable access begins here
let buffer = &source;
let parser = Parser { buffer };
source.push_str(" Pan");
println!("{:?}", parser);
// Both immutable and mutable access end here
}
如果您确定您的程序不会同时以可变和不可变方式主动访问资源,您可以通过将资源包装在 RefCell
中,将检查从编译时转移到运行时:
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct Parser {
buffer: Rc<RefCell<String>>
}
fn main() {
let source = Rc::new(RefCell::new(String::from("Peter")));
let parser = Parser { buffer: source.clone() };
source.borrow_mut().push_str(" Pan");
println!("{:?}", parser);
}
如果你计划在线程周围传递你的资源,你可以使用 RwLock
来阻塞线程直到资源可用:
use std::sync::{RwLock, Arc};
#[derive(Debug)]
struct Parser {
buffer: Arc<RwLock<String>>
}
fn main() {
let source = Arc::new(RwLock::new(String::from("Peter")));
let parser = Parser { buffer: source.clone() };
source.write().unwrap().push_str(" Pan");
println!("{:?}", parser);
}
另一方面,您应该更喜欢 &str
而不是 &String
关于reference - 用于处理对缓冲区的引用的惯用 Rust 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45796365/