不能像易变的那样借,因为它也像不可变的那样借

我在学拉斯特,我不太明白为什么这样不行。

#[derive(Debug)]
struct Node {
value: String,
}


#[derive(Debug)]
pub struct Graph {
nodes: Vec<Box<Node>>,
}


fn mk_node(value: String) -> Node {
Node { value }
}


pub fn mk_graph() -> Graph {
Graph { nodes: vec![] }
}


impl Graph {
fn add_node(&mut self, value: String) {
if let None = self.nodes.iter().position(|node| node.value == value) {
let node = Box::new(mk_node(value));
self.nodes.push(node);
};
}


fn get_node_by_value(&self, value: &str) -> Option<&Node> {
match self.nodes.iter().position(|node| node.value == *value) {
None => None,
Some(idx) => self.nodes.get(idx).map(|n| &**n),
}
}
}




#[cfg(test)]
mod tests {
use super::*;


#[test]
fn some_test() {
let mut graph = mk_graph();


graph.add_node("source".to_string());
graph.add_node("destination".to_string());


let source = graph.get_node_by_value("source").unwrap();
let dest = graph.get_node_by_value("destination").unwrap();


graph.add_node("destination".to_string());
}
}

(游乐场)

这里有个错误

error[E0502]: cannot borrow `graph` as mutable because it is also borrowed as immutable
--> src/main.rs:50:9
|
47 |         let source = graph.get_node_by_value("source").unwrap();
|                      ----- immutable borrow occurs here
...
50 |         graph.add_node("destination".to_string());
|         ^^^^^ mutable borrow occurs here
51 |     }
|     - immutable borrow ends here

这个来自 编程 Rust的例子和我的很相似,但是它很有效:

pub struct Queue {
older: Vec<char>,   // older elements, eldest last.
younger: Vec<char>, // younger elements, youngest last.
}


impl Queue {
/// Push a character onto the back of a queue.
pub fn push(&mut self, c: char) {
self.younger.push(c);
}


/// Pop a character off the front of a queue. Return `Some(c)` if there /// was a character to pop, or `None` if the queue was empty.
pub fn pop(&mut self) -> Option<char> {
if self.older.is_empty() {
if self.younger.is_empty() {
return None;
}


// Bring the elements in younger over to older, and put them in // the promised order.
use std::mem::swap;
swap(&mut self.older, &mut self.younger);
self.older.reverse();
}


// Now older is guaranteed to have something. Vec's pop method // already returns an Option, so we're set.
self.older.pop()
}


pub fn split(self) -> (Vec<char>, Vec<char>) {
(self.older, self.younger)
}
}


pub fn main() {
let mut q = Queue {
older: Vec::new(),
younger: Vec::new(),
};


q.push('P');
q.push('D');


assert_eq!(q.pop(), Some('P'));
q.push('X');


let (older, younger) = q.split(); // q is now uninitialized.
assert_eq!(older, vec!['D']);
assert_eq!(younger, vec!['X']);
}
69160 次浏览

你的问题的 MRE可以归结为:

// This applies to the version of Rust this question
// was asked about; see below for updated examples.
fn main() {
let mut items = vec![1];
let item = items.last();
items.push(2);
}
error[E0502]: cannot borrow `items` as mutable because it is also borrowed as immutable
--> src/main.rs:4:5
|
3 |     let item = items.last();
|                ----- immutable borrow occurs here
4 |     items.push(2);
|     ^^^^^ mutable borrow occurs here
5 | }
| - immutable borrow ends here

您遇到的 正是问题所在是 Rust 设计用来防止的。您有一个指向向量的引用,并试图插入到向量中。这样做可能需要重新分配向量的内存,从而使任何现有引用失效。如果发生这种情况,并且您使用了 item中的值,那么您将访问未初始化的内存,这可能会导致崩溃。

在这个 特别的例子中,您实际上并没有使用 item(或者原来的 source) ,所以您可以只是... ... 不调用那一行。我假设您这样做是出于某种原因,这样您就可以将引用包装在一个块中,这样它们就会在您再次尝试变异值之前消失:

fn main() {
let mut items = vec![1];
{
let item = items.last();
}
items.push(2);
}

在现代 Rust 中不再需要这个技巧,因为已经实现了 非词汇生命期,但是底层的限制仍然存在ーー当存在对同一事物的其他引用时,不能有可变的引用。这是 锈迹编程语言覆盖的 参考规则参考规则之一。一个修改后的示例仍然不能用于 NLL:

let mut items = vec![1];
let item = items.last();
items.push(2);
println!("{:?}", item);

在其他情况下,可以复制或克隆向量中的值。该项目将不再是一个参考,你可以修改向量,因为你认为合适:

fn main() {
let mut items = vec![1];
let item = items.last().cloned();
items.push(2);
}

如果类型不可克隆,可以将其转换为引用计数值(如 RcArc) ,然后可以克隆这些值。你可能需要也可能不需要使用 内部可变性:

struct NonClone;


use std::rc::Rc;


fn main() {
let mut items = vec![Rc::new(NonClone)];
let item = items.last().cloned();
items.push(Rc::new(NonClone));
}

这个来自 Programming Rust 的例子非常相似

不,不是,因为它根本不用参考资料。

参见

尝试把你的不变借入内块{ ... }。 这结束了街区后的借贷。

#[cfg(test)]
mod tests {
use super::*;


#[test]
fn some_test() {
let mut graph = mk_graph();


graph.add_node("source".to_string());
graph.add_node("destination".to_string());


{
let source = graph.get_node_by_value("source").unwrap();
let dest = graph.get_node_by_value("destination").unwrap();
}


graph.add_node("destination".to_string());
}
}