我希望能够构造包含对可变缓冲区对象的不可变引用的对象。以下代码不起作用,但说明了我的用例,是否有一个惯用的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);
}
答案 0 :(得分:2)
生锈借用检查器的黄金法则是:一次只有一个作者或多个读者可以访问资源。这可确保算法在多个线程中安全运行。
你违反了这条规则:
#[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
答案 1 :(得分:1)
通过改变source
,很难说出你想要实现的目标。我会假设你不希望它在解析器工作时发生吗?您可以随时尝试(取决于您的具体用例)将不可变的变量与额外的范围分开:
fn main() {
let mut source = String::from("Peter");
{
let buffer = &source;
let parser = Parser { buffer };
println!("{:?}", parser);
}
source.push_str(" Pan");
}
如果您不想使用RefCell
,unsafe
(或者只是在source
中保留对Parser
的可变引用并使用它),我和#39;我担心它不会比普通的重构好。
答案 2 :(得分:1)
要详细说明如何不安全地完成此操作,可以通过使用原始const指针来避免借用规则来实现您所描述的内容,这当然本质上是不安全的,因为您的概念是&# 39;描述是非常不安全的。如果你选择这条道路,有办法让它更安全。但如果安全性很重要,我可能会默认使用Arc<RwLock>
或Arc<Mutex>
。
use std::fmt::{self, Display};
#[derive(Debug)]
struct Parser {
buffer: *const String
}
impl Display for Parser {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let buffer = unsafe { &*self.buffer };
write!(f, "{}", buffer)
}
}
fn main() {
let mut source = String::from("Peter");
let buffer = &source as *const String;
let parser = Parser { buffer };
source.push_str(" Pan");
println!("{}", parser);
}